現在、もりけん塾にてJavaScriptを勉強させていただいております。その記録。
今回は課題24についての備忘録です。
考え方が間違っている箇所もあるかと思いますが、お気づきの際はご指摘いただければと思います。
課題24について
仕様
課題24の仕様
- バリデーションはここではなし
- ユーザー名、メールアドレス、パスワードの入力欄と利用規約に関するチェックボックス(画像参照)がある。
- 送信ボタンがあるが振るまいの実装はしないで良い
- 利用規約のテキストを押すと、モーダルが立ち上がり(前回作ったもので良い)、ダミーの利用規約がテキストとして読める。スクロールが一番下に行ったらチェックボックスはcheckedになる。もし開いてもスクロールが下まで行っていなければcheckedはfalseのまま
- checkedがtrueの場合送信ボタンを押下すると別ページの
register-done.html
に飛ぶ register-done.html
は画面のようなテキストになっている(画面は適当で、遷移できていることが分かれば良い。CSSも書かないでも良い)- これ以降の課題でログイン画面が登場する課題にはPRのわかりやすい所にユーザー名とpasswordなど示してください
制作物
コードはこちらから(codesandbox)※codesandboxではエラーが出る場合がありますが、リロードすれば動きます。
実装内容
【HTML】モーダルマークアップ
今回モーダルのアクセシビリティについて、勉強になったことを記録します。
レビューにて、divでモーダルを作成する際には、「role=”dialog”」が必要だと教わりました。
role=”dialog”について
ダイアログ要素をダイアログ (
MDNよりdialog
)ロールでマークアップすると、支援技術がダイアログのコンテンツをページコンテンツの残りの部分からグループ化して分離されたものとして識別するのに役立ちます。 ただし、role="dialog"
だけを追加するだけでは、ダイアログをアクセス可能にするには不十分です。 さらに、次のことを行う必要があります。
・ダイアログには適切なラベルを付ける必要があります。
・キーボードのフォーカスを正しく管理する必要があります。
モーダルをdivでマークアップする際には、そこが他とは分離された要素グループ(モーダル)だということを明示するべきとのこと。また、role=”dialog”属性を付与した際には、適切なラベル付と、キーボードフォーカスについても管理する必要があるようです。
確かに、スクリーンリーダーでサイト読み上げる際にしっかりと明示されていないとそれがなんの要素であるか理解できませんし、また、キーボード操作の際に、それ単体でもしっかりとフォーカスを当てることができなければ不便です。
今回はラベル付については適切だと思われる箇所につけ、キーボード操作については次回以降の課題にしようと思います。
//モーダルのマークアップ箇所
//role属性を付与し、titleとdescribe箇所を指定
<div role="dialog" aria-labelledby="dialogTitle" aria-describedby="dialogDesc" id="js-modal" class="modal hidden" >
<button type="button" id="js-close" class="close_button">×</button>
<div class="modal_container" id="js-modal_container">
//titleとdescribe箇所をidにて指定する
<h2 id="dialogTitle">利用規約</h2>
<div id="dialogDesc" class="modal_content">
<p>
この利用規約(以下,「本規約」といいます。)は,_____(以下,「当社」といいます。)がこのウェブサイト上で提供するサービス(以下,「本サービス」といいます。)の利用条件を定めるものです。登録ユーザーの皆さま(以下,「ユーザー」といいます。)には,本規約に従って,本サービスをご利用いただきます。
</p>
</div>
<div class="modal_content">
<h3>第1条(適用)</h3>
<ol>
<li>本規約は,ユーザーと当社との間の本サービスの利用に関わる一切の関係に適用されるものとします。</li>
<li>
当社は本サービスに関し,本規約のほか,ご利用にあたってのルール等,各種の定め(以下,「個別規定」といいます。)をすることがあります。これら個別規定はその名称のいかんに関わらず,本規約の一部を構成するものとします。
</li>
<li>本規約の規定が前条の個別規定の規定と矛盾する場合には,個別規定において特段の定めなき限り,個別規定の規定が優先されるものとします。</li>
</ol>
</div>
//////////////////
// 途中割愛
////////////////////
<div class="modal_content">
<h3>第15条(準拠法・裁判管轄)</h3>
<ol>
<li>本規約の解釈にあたっては,日本法を準拠法とします。</li>
<li>本サービスに関して紛争が生じた場合には,当社の本店所在地を管轄する裁判所を専属的合意管轄とします。</li>
</ol>
</div>
<div class="modal_content">
<p>以上</p>
</div>
</div>
</div>
【HTML】フォームのマークアップについて
inputタグlabelタグについて
基本的な部分が理解できていなかった(忘れてた)ので備忘録。
labelタグとinputタグは紐付けする必要があり、labelタグのfor=””/inputタグのid=””を同じにすることで紐付けができる。また、今回、checkboxについては、labelタグの中にinputタグを入れて関連づけているため、ここではfor=””とid=””での紐付けはしない。
inputタグのtypeについては適切なものを入れる。今回は、
ユーザー名→text
メールアドレス→email
パスワード→password
チェックボックス→checkbox
とした。ここ当初適当にしていて間違っていた。。
<div id="js-wrapper" class="wrapper">
<h1>会員登録</h1>
<form method="post">
<div>
<ul>
<li>
<label for="name">ユーザー名</label>
<input type="text" id="name" name="user_name" />
</li>
<li>
<label for="mail">メールアドレス</label>
<input type="email" id="mail" name="user_email" />
</li>
<li>
<label for="password">パスワード</label>
<input type="password" id="password" name="user_password" />
</li>
</ul>
</div>
<div class="checkbox">
<label>
<input type="checkbox" id="js-checkbox" disabled />
<a href="#" id="js-terms-textlink">利用規約</a>を読み同意しました
</label>
</div>
<button type="button" id="js-submit-button" class="submit_button">送信</button>
</form>
</div>
【JS】Intersection Observer
今回スクロールイベントについてはIntersection Observer APIを使用しました。
root(監視エリア)を指定し、対象の要素が監視エリア内に入ってきたら処理を実行する。(ざっくり概要)
参考記事:
Intersection Observer API
JSでのスクロール連動エフェクトにはIntersection Observerが便利
今回の仕様としては、全てをスクロールしたらチェックボックスにチェックが入るということなので、ラストのコンテンツが監視内に入ってきたら処理を実行するという考え方にしました。
const options = {
root: document.getElementById('js-modal'),
threshold: 1
};
const checkWhenIntersect = ([entry]) => {
if (entry.isIntersecting) {
checkbox.checked = true;
checkbox.disabled = false;
}
}
//引数は1つなのでfor each使用する必要はないので却下
//const checkWhenIntersect = (entries) => {
// entries.forEach(entry => {
// if (entry.isIntersecting) {
// checkbox.checked = true;
// checkbox.disabled = false;
// }
// });
//}
const observer = new IntersectionObserver(checkWhenIntersect, options);
observer.observe(modalContainer.lastElementChild);
//ターゲット指定ではなく、modalの中の最後の要素(lastElementChild)にて指定に変更
//observer.observe(target);
submitButton.addEventListener('click',function(e){
checkbox.checked ? window.location.href = './register-done.html' : e.preventDefault();
})
レビューPOINT① 引数の渡し方
監視エリアにターゲットが入ってきたら、指定したコールバックが呼び出され、監視ターゲットが引数として渡されます。元々記事を参考にforEachを使用していましたが、今回は監視ターゲットは1つなのでforEachを使用する必要はないとご指摘いただきました。
forEachを外して、引数を分割代入で入れると良いとのアイディアいただき、なるほど〜となりました。
実は自分でもforEachは今回必要ないかなと思ったのですが、外すとうまく動いてくれずなんでだろうと思っていたのですが、引数は配列で渡ってくるので、値を取り出してあげないとダメなんだと気づきました。
レビューPOINT② ラストのコンテンツの指定の仕方
当初は、ラストのコンテンツにクラスを付与してターゲットを指定していましたが、lastElementChild(要素の最後の子を返す)が使えると教えていただきました。そうすることでコンテンツが増えても、クラスの修正をしなくてすみます。ナイスアイディア。。!
【CSS】モーダルのスタイルの当て方
モーダルの四つ角をラウンドさせていたのですが、左上しか効いていないのではとレビューを受けました。
自分の画面では全てラウンドになっていたので、あれ?と思ったのですが、話を精査したところ、macの設定でスクロールがある場合、スクロールバーを表示させるかしないかという設定があるらしいです。(私のPCではバー表示なし、レビューしてくれた方は表示ありという設定だった模様)そういう場合もあるんだなあと気づくことができました。
スクロールバーがある場合でも、ラウンドを効かせることができるとのことで、ウィンドウの外枠に角丸を指定、インナーでスクロールさせると角丸が反映されると教えていただきました。
基本的にCSSの当て方が悪かったんだなと思いました(見た目がOKだったので何も考えていませんでした…)設定についても調べていただき、ここは色々発見がありました、ありがとうございます…!!
.modal {
max-width: 500px;
width: 100%;
height: 350px;
border-radius: 10px;
position: relative;
margin: 0 auto;
z-index: 2;
top: 13%;
overflow: hidden;
}
.modal_container {
width: 100%;
height: 100%;
background: #fff;
overflow: scroll;
padding: 30px;
}
/* .modal {
max-width: 500px;
width: 100%;
position: relative;
margin: 0 auto;
z-index: 2;
top: 13%;
}
.modal_container {
background: #fff;
overflow: scroll;
height: 350px;
border-radius: 10px;
padding: 30px;
} */
後記
今回JSもそうですが、マークアップの方でも基本的なところをご指摘いただき、大変勉強になりました。また、モーダルのアクセシビリティについても、しっかりと考えなければいけないのだと知りました。今回は仕様を満たすことで精一杯でしたが、今後考慮しなければいけない箇所だとしっかり留め勉強していこうと思います。
c.sakyou