文章を全部読むまで押せないチェックボックスを作ってみよう

2022年4月20日 2023年11月8日
カテゴリ: プログラミング
JavaScript CSS HTML

サイトに会員登録するとき、規約等の文章を下までスクロールしないと押せないチェックボックスやボタンってよくありますよね。
「文章をちゃんと全部読んで同意したよね?」ってさせるアレです。
(文章を最後までスクロールしないと次の画面へ進めないので、この仕組みを知らないとちょっと戸惑いますよね。)

こんな感じのやつです。

今回はこれを作ってみましょう。

HTML と CSS で画面を作る

まずは、文章を下までスクロールしなくてもチェックできるチェックボックスを作ってみましょう。
こんな感じです。

HTML と CSS はこんな感じになります。

HTML
<div>
  <textarea>文章</textarea>
  <div>
    <label for="cb1"><input type="checkbox" id="cb1">同意する</label>
  </div>
</div>
CSS
textarea {
  width: 300px;
  height: 100px;
  resize: none;
}

文章を下までスクロールしないとチェックできない状態にするためには初期状態でチェックできないようにしておいて、下までスクロールした段階で JavaScript の処理でチェックできる状態に変更するという方法が考えられます。

チェックボックスをチェックできない状態にするには input 要素の disabled プロパティを有効にすればよいだけです。
具体的にいうと input タグの中に disabled を入れるだけで OK です。

HTML
<label for="cb1"><input type="checkbox" id="cb1" disabled>同意する</label>

チェックボックスを disabled にすると色が薄くなって視覚的にもチェックできない状態だと分かるかと思います。

もっと分かりやすくするためにラベル色も変えてしまいましょう。
label は disabled プロパティがないので、クラスを追加して CSS で色を変えるようにします。

HTML
<div>
  <label for="cb1" class="disabled"><input type="checkbox" id="cb1" disabled>同意する</label>
</div>
CSS
.disabled {
  color: lightgray;
}

ここで追加したクラスを JavaScript の処理で取り除けばラベルの色は元に戻ります。

JavaScript の処理を作る

JavaScript の処理は下記の 3 つが必要になります。

  1. 文章 (textarea) がスクロールしたときに処理を行う
  2. 最後までスクロールされたか判定する
  3. チェックボックスをチェックできる状態にする

1. 文章 (textarea) がスクロールしたときに処理を行う

「要素に何か変化があったとき」をトリガーにして処理を行うためには addEventListener を使用します。
「スクロール」をトリガーにする場合は scroll イベントを指定します。

JavaScript
const textArea = document.querySelector("textarea");
textArea.addEventListener("scroll", 実行したい処理(イベントハンドラ));

2. 最後までスクロールされたか判定する

要素の現在のスクロール位置 (表示されていない最上部から表示されている最上部まで) は scrollTop で取得できます。
要素の表示されていない部分も含めた高さは scrollHeight で取得できます。
要素の表示されている部分のうち、margin や border 等を抜いた高さは clientHeight で取得できます。

これらの関係は次のような感じです。

単純に考えれば判定式は次のようなものが考えられます。

JavaScript
if(scrollTop == scrollHeight - clientHeight){...}

ですが、scrollTop は小数点を含む実数値 (または整数値)、scrollHeight と clientHeight は小数点を丸めた整数値で返ってきます。
そのため上記の判定式では正しく判定できません。

要素が完全にスクロールされたかどうかの判定

上記サイトを参考に、次のようにしましょう。

JavaScript
if(Math.abs(element.scrollHeight - element.clientHeight - element.scrollTop) < 1){...}

3. チェックボックスをチェックできる状態にする

チェックボックスをチェックできない状態にするために、disabled を有効にしましたが内部的な状態は disabled プロパティが true になっているだけです。
つまり、これを無効にするには disabled を false にすればよいわけです。

JavaScript
const checkBox = document.querySelector("input[type='checkbox']");
checkBox.disabled = false;

また、チェックボックスをチェックできる状態に戻す段階でラベルの表示色も戻したいので、ラベルの色を変えるために追加したクラスを取り除きます。
クラスを取り除くには classList.remove を使用します。

JavaScript
const label = document.querySelector("label");
label.classList.remove("disabled");

まとめると

以上をまとめると次のようになります。

JavaScript
const textarea = document.querySelector("textarea");
const checkbox = document.querySelector("input[type='checkbox']");
const label = document.querySelector("label");
textarea.addEventListener("scroll", func=()=>{
  if(Math.abs(textarea.scrollHeight-textarea.clientHeight-textarea.scrollTop)<1){
    checkbox.disabled = false;
    label.classList.remove("disabled");
  }
});

チェックボックスではなくボタンにすることも出来ます。


チェックボックスをチェックしないと押せないボタンを作ることもできます。(詳しくはこの記事のソースを見てね)


関連の記事

【Django】CSS や JavaScript の変更が反映されないときの対処法

ラジオボタンを未選択の状態にする方法を考えよう

CSSで色見本のアイコンを作ろう

【CSS】連続する <span> 要素の間に隙間ができてしまう問題について