Ateam Brides Inc. Advent Calendar 2021の10日目はデザイナーの綿貫(@xrxoxcxox)がお送りします!
この記事の概要
ボタンっぽい見た目の要素をクリックしたら検索フォームが動くとか自分のプロフィールを更新するとか、そういうインターフェースはたくさんありますよね。
ときどきdiv
やspan
要素にaddEventListener('click', function)
をつけて動かしているのを見かけるのですが、結局改善を求められるはずでしかも工数がかかります。
というわけでシンプルにbutton
を使いましょう、と啓蒙する記事です。
伝えたいこと
ボタンっぽい役割の要素であればbutton
タグを使いましょう!
この1点のみです!
div
やspan
でボタンっぽい要素を作るとどうなるの?
- タブキーでフォーカスを当てられない
-
enter
やspace
でボタンのアクションを実行できない - スクリーンリーダーが適切に読み上げてくれない
というわけで非常に使いづらくなります。
あなたの作っているプロダクトを使ってくれている人から「ボタンが操作できないので修正してもらえませんか?」と意見をいただければラッキーで、上手く使えないからと静かに去ってしまう可能性もあるかもしれません。
特にキーボードのみで操作している人にとってはクリティカルな問題になり得ます。
div
やspan
でボタンっぽい要素を作った場合、改善する方法
まずは最初の時点のコードを載せます
<div id="div" class="button">ボタン風のdiv</div>
const div = document.getElementById('div');
const divClick = () => {
alert('divがクリックされました');
};
div.addEventListener('click', divClick);
クリックだけならbuttonとdivの差は無く見える |
---|
tabindex
をつける
- <div id="div" class="button">ボタン風のdiv</div>
+ <div id="div" class="button" tabindex="0">ボタン風のdiv</div>
tabindex
をつけないと、そもそもタブキーでフォーカスを当てることができません。
タブキーでリズミカルに進んでいたのに、アクションを起こすためのボタンでつんのめってしまいます。
tabindexが無いのでフォーカスがあたらない | tabindexがあるのでフォーカスがあたる |
---|---|
keydown
のeventListenerを登録する
keydown
がないと、せっかくフォーカスがあたってもキーボードからアクションを起こせません。
enter
とspace
を登録して、クリックとは別な処理として書く必要が出てきます。
const div = document.getElementById('div');
const divClick = () => {
alert('divがクリックされました');
};
+ const divKeydown = (e) => {
+ if (e.keyCode === 13 || e.keyCode === 32) {
+ alert('divに対してキーが押されました');
+ }
+ };
div.addEventListener('click', divClick);
+ div.addEventListener('keydown', divKeydown);
keydownが無いのでenterを押しても反応がない | keydownがあるのでenterを押すと反応する |
---|---|
button
のroleを追加する
- <div id="div" class="button" tabindex="0">ボタン風のdiv</div>
+ <div id="div" class="button" tabindex="0" role="button">ボタン風のdiv</div>
操作するタイミングでは問題がなくなりましたが、まだマークアップとしてはdiv
でしかないのでスクリーンリーダーが上手く認識してくれません。
しっかりbutton
であると明示する必要があります。
※少し見づらいですが、右下に出してあるVoiceOverに表示されている内容が変わっています。
roleが無いのでdivと認識されたまま | roleがあるのbuttonと捉えられる |
---|---|
上記の内容はbutton
タグなら全く実施しなくてOK
たとえば、何かの処理を作る度にキー押下の判定を加えるのは面倒ですよね?(仮にユーティリティな関数として切り出したとしても、毎回呼び出すこと自体が面倒だと思います)
けどこれらは正しいマークアップ、つまりbutton
タグを使ってさえおけば何も実施しなくてOKなんです。
使わない手はありませんね。
まとめ
- ボタンっぽい要素を
div
やspan
で作ってしまうと- タブキーでフォーカスを当てられない
-
enter
やspace
でボタンのアクションを実行できない - スクリーンリーダーが適切に読み上げてくれない
-
button
で作れば上記の問題は起きない