JavaScriptで最後までスクロールしないとチェックできない規約を作る

利用規約と同意のチェックボタンを作る機会があり、その際に調べたことのまとめ

## そもそもスクロール必須にするべきなのか？
これは少し気になったので、事例について調べてみました。

弁護士の方?が書いている内容で、適当にチェックだけできるような状態はよくなさそうだと思いました。
[利用規約の有効性を基礎付ける「同意」の取得方法](http://bengoshi-sakao.com/page/kiyaku02/)
> 利用規約への同意を取得する際には、ユーザーに利用規約をきちんと読んでもらい、これに同意した人だけがサービスを利用できるような仕組みにしておくことが重要です。

> 例えば、規約のリンクを貼ってあるだけよりも、規約全文をスクロールしなければチェックボックスに辿りつかないようにしてある方が、「読んでなかった」と主張されるリスクは減少します。

こちらに裁判例がまとめられていました。(3件しか見つからなかったそうです)
ここだけみると、スクロールが必須だったのかはわからないですが、どうやら規約の変更についても問題になることがあるようですね。
[「利用規約に同意」画面のUIデザインについて言及された日本の裁判例まとめ](https://www.cloudsign.jp/media/20171124-riyoukiyakusaibanrei/)

> １件目は、伊藤雅浩（@redipsjp）先生からtwitterで情報を提供いただいた裁判例です。昔ながらの、利用規約がスクロールするテキストボックスの下に、承諾ボタンがレイアウトされたもの。裁判所は、このレイアウトなら規約に目を通すのは当然でしょう、と断じています。

## ピュアJSでやってみる
### まずはスクロールできるdiv要素を作ってみる
cssの[overflow-y](https://developer.mozilla.org/ja/docs/Web/CSS/overflow-y)をscrollにすることで、スクロールできる要素を作成できます。

<p class="codepen" data-height="265" data-theme-id="0" data-default-tab="html,result" data-user="buntafujikawa" data-slug-hash="eqZodo" style="height: 265px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="eqZodo">
  <span>See the Pen <a href="https://codepen.io/buntafujikawa/pen/eqZodo/">
  eqZodo</a> by buntafujikawa (<a href="https://codepen.io/buntafujikawa">@buntafujikawa</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://static.codepen.io/assets/embed/ei.js"></script>

### 最後までスクロールされたかを判定する
次に先ほど作成したスクロールができる要素が、一番下までスクロールされたかを判定します。

#### 判定方法
下記の計算で下までスクロールをしたかどうかわかりそうです。
[clientHeight](https://developer.mozilla.org/ja/docs/Web/API/Element/clientHeight) + [scrollTop](https://developer.mozilla.org/ja/docs/Web/API/Element/scrollTop) = [scrollHeight](https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollHeight)

clientHeight
> 要素内のピクセル単位の高さ (height) を返します

scrollHeight
> a measurement of the height of an element's content

scrollTo
> the number of pixels that an element's content is scrolled vertically.

![scrollHeight.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/144753/75c416a7-139a-0312-5a43-d64c2cdfa0c1.png)


#### スクロール時のイベント取得
[onscroll](https://developer.mozilla.org/en-US/docs/Web/API/GlobalEventHandlers/onscroll)でスクロールをした時のイベントを取得できます。

onscrollと先ほどの判定式を組みあわたものです。
<p class="codepen" data-height="265" data-theme-id="0" data-default-tab="js,result" data-user="buntafujikawa" data-slug-hash="gVLwjg" style="height: 265px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="gVLwjg">
  <span>See the Pen <a href="https://codepen.io/buntafujikawa/pen/gVLwjg/">
  gVLwjg</a> by buntafujikawa (<a href="https://codepen.io/buntafujikawa">@buntafujikawa</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://static.codepen.io/assets/embed/ei.js"></script>

#### 最終的にできたもの
単純にif文の条件分岐を入れただけですが
<p class="codepen" data-height="265" data-theme-id="0" data-default-tab="js,result" data-user="buntafujikawa" data-slug-hash="oKYzQX" style="height: 265px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="oKYzQX">
  <span>See the Pen <a href="https://codepen.io/buntafujikawa/pen/oKYzQX/">
  oKYzQX</a> by buntafujikawa (<a href="https://codepen.io/buntafujikawa">@buntafujikawa</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://static.codepen.io/assets/embed/ei.js"></script>

## 注意点
実はこのまま使用をすると、iOSのsafariでものすごくカクカクしたスクロールになってしまいます。
デフォルトで指が触れている時しかスクロールしないようになっているそうです。

下記のCSSを使えば滑らかなスクロールになりユーザーとしては使いやすいのですが、非標準であり使うかどうかは個別判断が必要になると思います。
[-webkit-overflow-scrolling](https://developer.mozilla.org/ja/docs/Web/CSS/-webkit-overflow-scrolling)

> この機能は標準ではなく、標準化の予定もありません。公開されているウェブサイトには使用しないでください。ユーザーによっては使用できないことがあります。実装ごとに大きな差があることもあり、将来は振る舞いが変わるかもしれません。

OSSで使われているのかな？と思って調べてみたら、スター2000超えのライブラリでも使用されており、issueで使わない方が良いのではと問題提起されていました。
[eact-custom-scrollbars](https://github.com/malte-wessel/react-custom-scrollbars/issues/255)

もし不具合が発生した場合にはそもそも規約に同意ができなくなってしまうので、使用する場合には自己責任でお願いします。

## おわりに
この記事を書いてから気が付いたのですが、[Element.scrollHeight
](https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollHeight)の下の方にdemoが記載されてて、ほぼ同じようなコードの例が載っていました :joy: 
ちゃんと最後までみておけばよかった...