トピックを検索
キーボードで操作できないカスタムチェックボックス
登録フォームが角の丸い独自のチェックボックスを描き、本物のチェックボックスをdisplay: noneで隠しているため、マウスではチェックできても、Tab、Space、スクリーンリーダーには見つかりません。
input[type="checkbox"] { display: none; } 問題
キーボード、スイッチ、スクリーンリーダーの利用者は、ボックスに到達することもチェックすることもできないため、規約に同意できず、アカウントを作れません。
登録フォームのデザインには、独自のチェックボックスが描かれています。ブランドの色である紫の地に白いチェックマークが入る、角の丸いボックスです。ブラウザー標準のボックスはブラウザーごとに見た目が違い、ページのほかの部分とも合わないからです。ボックスは二つあります。「お得な情報をメールで受け取る」と、必須の「利用規約に同意する」で、その下に「アカウントを作成」ボタンがあります。開発者は描かれたとおりに作ります。各ラベルの中に、display: none で隠した本物のチェックボックスと、ボックスとして描いた span を置き、隠したチェックボックスがチェックされるとその span にチェックマークを描きます。ラベルをクリックするとチェックボックスは見えなくてもチェックされるので、どちらの行をクリックしてもチェックが付きます。マウスで使う限り、フォームは正しく見え、正しく動きます。
マウスを使わずに、メールアドレスの欄からTabを押します。フォーカスは「アカウントを作成」へ直接移り、二つのボックスは飛ばされます。Spaceでチェックするものもありません。スクリーンリーダーは「利用規約に同意する」を、チェックボックスも状態もない一行の文として読みます。「アカウントを作成」を押しても何も起きません。規約のボックスは必須なので、ブラウザーはフォームの送信を止めますが、存在しないボックスにはフォーカスを移せません。Chromeはメッセージも出さず、開発者ツールのコンソールに「An invalid form control with name='terms' is not focusable.」と1行出るだけです。キーボードの利用者は、アカウントをまったく作れません。
display: none は、チェックボックスをページから完全に取り除きます。Tabの順序からも、アクセシビリティツリーからも外れ、画面に残るのはチェックボックスの絵だけです。マウスはラベルを通じてその機能に届きますが、キーボードは届かないため、達成基準2.1.1 キーボードを満たしません。また、チェックボックスに見えるものが、名前、役割、チェックの状態を持つチェックボックスとして公開されていないため、4.1.2 名前・役割・値も満たしません。その行がチェックできる選択肢であることが絵でしか示されず、コードにないため、1.3.1 情報及び関係性も満たしません。
同じデザインは、ほかの作り方でも同じように失敗します。
- チェックボックスを
visibility: hiddenやhidden属性で隠す。どちらもTabの順序とアクセシビリティツリーから外れ、ラベルをクリックすればチェックは付きます。 - inputを使わず、クリックのハンドラーを付けた
divをチェックボックスとして描く。キーボードからは届かず、何も読み上げられず、スクリプトで加えない限りフォームと一緒に送信もされません。 - 配送方法などのラジオボタンを、ラジオボタンを隠した選択肢のカードとして描く。Tabに加えて、グループの中で選択を移す矢印キーも使えなくなります。
規約への同意、年齢の確認、配送方法の選択など、必須の選択は登録、購入手続き、設定のページにあります。マウスでしかチェックできないと、フォームはそのボックスで終わり、画面にはその理由が何も示されません。
10グループ中2グループに影響
隠れたinputは、ほとんどのチェックの対象外です。axeは表示されているものを調べるので、display: none のチェックボックスは調べず、横のラベルはただの文で、問題はありません。失敗は欠けているものにあり、あるものを調べても何も見つかりません。EaseWebの診断は、ラベルが表示されているのに隠れているチェックボックスやラジオボタンを ew:hidden-native-input として報告します。修正を頼むと、コード生成AIはラベルや描いたボックスに tabindex="0" を付けることがあります。Tabはそこに止まるようになりますが、ラベルはSpaceでチェックされず、チェックボックスも状態も読み上げられません。display: none を visibility: hidden に変えても何も変わりません。マウスを使わずに、フォームを試してください。
試してみる
Tabで登録フォームを移動し、Spaceで各ボックスをチェックしてから、「アカウントを作成」でEnterを押してください。
マウスなら、どちらのボックスもチェックできます。下の欄に、フォーカスの移動に合わせたスクリーンリーダーの読み上げが出ます。マウスを使わずに規約に同意できますか?
問題あり 修正できますか?
スクリーンリーダーの読み上げ:
(Tabでフォームを移動)
修正方法
本物のinputをページに残し、その上に描くか、ボックスの上に重ねるか、accent-colorで色を付けます。
- 1本物のチェックボックスやラジオボタンを、ページ、Tabの順序、アクセシビリティツリーに残す。
- 2チェックマークとフォーカスの枠は、input自体のチェックとフォーカスの状態から描く。
- 3チェックしたことを色だけでなく、チェックマークや点で示す。
<form action="/sign-up" method="post"> … <label class="check"> <input type="checkbox" name="offers"> <span class="box"></span> お得な情報をメールで受け取る </label> <label class="check"> <input type="checkbox" name="terms" required> <span class="box"></span> 利用規約に同意する </label> <button type="submit">アカウントを作成</button></form>Input自体に描いたボックス
<form action="/sign-up" method="post"> … <label class="check"> <input type="checkbox" name="offers"> お得な情報をメールで受け取る </label> <label class="check"> <input type="checkbox" name="terms" required> 利用規約に同意する </label> <button type="submit">アカウントを作成</button></form>この方法を選ぶ理由:まずHTMLの要素を使う
ラベルをクリックすると隠したチェックボックスがチェックされ、ボックスにチェックマークが描かれます。しかし display: none のため、チェックボックスはTabの順序にもアクセシビリティツリーにもありません。キーボードは届かず、スクリーンリーダーはその存在を知りません。
appearance: none はブラウザーの描画だけを取り除き、チェックボックス自体は残すので、CSSで同じ角の丸いボックスとチェックマークをその上に描けます。何も隠していないため、Tabはボックスに止まり、Spaceでチェックでき、スクリーンリーダーは「利用規約に同意する、チェックボックス、チェックなし、必須」のように読み上げ、ブラウザーは必須であることを伝えるためにボックスへフォーカスを移せます。チェックマークと枠はチェックボックス自体の :checked と :focus-visible から描くので、見た目と読み上げがずれません。
三つとも適合します。特別な理由がなければ、input自体にボックスを描きます。要素が一つなので何も隠さず、ボックスの上に置いたり横に並べ続けたりする別の要素もなく、ブラウザーのフォーカス、タッチでの位置、フォームの動作が、目に見えるボックスと一緒にあります。ほぼすべての独自のチェックボックスでこれを勧める理由はここにあります。アイコンやSVGで描いたチェックマークなど、inputには入れられないものをボックスに入れる場合や、コンポーネントのマークアップを変えられない場合は、描いたボックスを残してinputを上に重ねます。その場合は、ボックスをチェックボックスのすぐ後に置き、チェックボックスをボックスの上に置き続けます。ブランドに必要なのがボックスの色だけの場合や、大きなサイトの最初の一歩としては accent-color を使います。問題を一度にすべての場所から取り除け、描いたボックスは後から加えられます。
ラジオボタンにも同じ三つの修正が使えます。appearance: none と border-radius: 50% でinputに円を描いて点を :checked から描くか、見た目だけ隠したラジオボタンの後に描いた円やカードを置くか、ブラウザーのラジオボタンに accent-color で色を付けます。各グループを legend のある fieldset に入れ、ラジオボタンに同じ name を付けます。そうするとTabはグループに一度だけ止まり、矢印キーで選択が移ります。これが、隠したラジオボタンのグループで失われるものです。選択肢のカードは、カード全体をラベルの中に入れてどこをクリックしても選べるようにし、ラジオボタンの円をカードの中に見えるように残します。
Windowsのコントラスト テーマでは、ブラウザーが塗りをページの背景色に置き換え、影を取り除きます。ここでのチェックマークは枠線で描いており、枠線はブラウザーが利用者の配色の色で描き直すため、紫の塗りが消えても、チェックしたボックスにはチェックマークが残ります。background-color と clip-path やマスクで塗りとして描いたチェックマークや点は、塗りと一緒に消えます。@media (forced-colors: active) の中で background-color: CanvasText を指定してください。同じ理由で、フォーカスの枠は box-shadow ではなく outline で描きます。
required は本物のチェックボックスに残します。チェックボックスがページにあれば、フォームの送信時にブラウザーがそこへフォーカスを移し、何が足りないかを伝えられます。隠してあると、メッセージを出す場所がありません。フォーム独自のエラーメッセージを出す場合は、描いたボックスではなくチェックボックスに関連付けます。
コンポーネントライブラリやテーマには、隠したinputが含まれていることがよくあります。コンポーネントの名前ではなく、出力されたマークアップを確認してください。スタイルを付けたラベルの横に display: none や hidden のチェックボックスがあれば、名前が何であれ失敗です。隠したチェックボックスとラベルで開くメニュー、CSSだけで作る「チェックボックスハック」も同じように失敗します。開いているか伝わらない表示・非表示ボタンで説明しているように、開いているかを伝えるボタンで作ります。
AI コーディングアシスタントで修正しますか? このガイドを Markdown で取得、または全ガイドをコーディングエージェントで使う。
デザインの案
チェックボックスはどんな見た目にもできます。本物が残っていれば。
サイトでよく見るチェックボックスとラジオボタンの描き方を6通り並べました。クリックしてから、マウスを使わずにTab、Space、矢印キーで試してください。4つは適合します。1つはTabで飛ばされ、1つは選択を淡い色だけで示します。
デザインファイルで
- 描いたボックス、チップ、色見本、カードには、チェックボックスかラジオボタンかを書く。本物を使って作られるように。
- すべての選択肢を、Tabで到達したときのフォーカスの枠付きで描く。
- チェックや選択は、色に加えてチェックマーク、点、輪で示し、白黒でも確認する。
- ボックスの枠線とページとのコントラスト比を横に書く。最低3:1。例の灰色の枠線は4.83:1。
- Windowsのハイコントラストモードでの選択肢を描く。塗りが消えても、チェックマーク、点、枠線が見えるように。
合格
- チェックマークが付く絞り込みチップ オフは#6b7280の枠線のピル(4.83:1)、オンは紫の枠線と淡い塗りに、言葉の前のチェックマークが付きます。文字は#3730a3で、塗りに対して8.88:1です。色がなくてもチェックマークでオンと分かり、チップ全体がチェックボックスなので、どこをクリック、タップしても、Spaceでも切り替わります。
- ラジオボタンが見える配送方法のカード 各カードが一つのラジオボタンで、どこをクリックしても選べます。角の円は残し、4.83:1の枠線の中に、選んだときは紫の点が入るので、淡い塗りがなくても選択が分かります。選んだカードの枠線も紫になります。Tabはグループに一度だけ止まり、矢印キーでカードの間を移動します。
- 輪とチェックマークの付く色見本 ラジオボタンとして作った丸い色見本で、選んだものは#111827の輪(白に対して17.74:1)で囲まれ、中にチェックマークが付き、「カラー」の後に色の名前が出ます。色を見分けにくい人は名前で読み取れ、矢印キーで色の間を移動できます。
- チェックマークが描かれる丸いToDoのチェック チェックすると円が紫になり、白いチェックマークが0.3秒で描かれて止まり、タスクに#6b7280の取り消し線が付きます。白黒でもチェックマークと線で完了と分かります。動きを減らす設定では、チェックマークはそのまま現れます。
不合格
- ラジオボタンを隠したサイズのタイルWCAG 2.1.1 S、M、L、XLを枠線のタイルにし、選んだものを#111827で塗ります。クリックではサイズを選べますが、その下のラジオボタンが隠れているため、Tabは4つとも素通りし、スクリーンリーダーには文字しか聞こえません。Tabで試してください。
- 淡い色だけで選択を示すプランのカードWCAG 1.4.1 ラジオボタンは本物なのでキーボードでは使えますが、何も描かれていません。選んだプランは#eef2ffの淡い塗りだけで示され、隣の白いカードとの差は1.12:1です。白黒、ハイコントラストモード、白っぽく見える画面では、二つのカードが同じに見えます。
修正の確認
5つの確認
確認方法: キーボード、スクリーンリーダー、マウス、強制配色、タッチ
OS、ブラウザーと支援技術のバージョン、ビルド、実施日、各手順の実際の結果を記録してください。共通のフォームコンポーネントやテーマを変更した際は、再度確認します。
制限
このサンプルは、どのアプリケーションでも同じ結果になることを保証するものではありません。CSSは最小限の例なので、ボックスの大きさ、枠線とフォーカスの枠のコントラストを実際の配色で確認してください。ARIAで作り直して状態を誤って伝えるチェックボックスは別の問題で、読み上げを誤らせる、無効なARIAで扱います。設問が結び付いていない選択肢のグループは設問名がないラジオボタンとチェックボックスのグループで、スイッチとして描いたチェックボックスはオンかオフかが伝わらないトグルスイッチで扱います。キーボード、スクリーンリーダー、コントラスト テーマで、フォーム全体を確認してください。
よくある問題を再現した学習用のサンプルです。実在のクライアントの診断結果ではありません。コードは出発点となる実装例のため、実際の製品でも確認してください。ここでは支援技術でのテスト結果は報告していません。
参考資料
- WCAG Understanding: keyboard(新しいタブで開きます)
- WCAG Understanding: name-role-value(新しいタブで開きます)
- WCAG Understanding: info-and-relationships(新しいタブで開きます)
- developer.mozilla.org: appearance(新しいタブで開きます)
- developer.mozilla.org: accent-color(新しいタブで開きます)
- developer.mozilla.org: forced-colors(新しいタブで開きます)
- sarasoueidan.com: inclusively-hiding-and-styling-checkboxes-and-radio-buttons(新しいタブで開きます)
- ARIA APG: radio(新しいタブで開きます)
コードを更新しても、使いやすさを保つために
ガイドの内容を、コーディングエージェントやCIで使える開発ルールにまとめます。更新後は、キーボードとスクリーンリーダーで再テストし、問題が再発していないか確認します。