テストページに関する注意
このページには、テストおよびデモのために意図的にアクセシビリティ上の問題を含む実装例が含まれています。
これらの例を本番サイトで使用しないでください。アクセシビリティのガイドラインやベストプラクティスに反します。
このページは Accessibility Visualizer 拡張機能と併用することで、開発者がアクセシビリティの問題を発見・理解するのを支援する目的で作られています。
テスト用ページ
このページは Accessibility Visualizer 拡張機能の動作確認を目的としたテストページです。アクセシビリティ上の課題がある様々な実装例を含み、拡張機能が問題点をどのように可視化し、改善の手がかりを提示するかを確認できます。
カテゴリー
見出し
見出しはコンテンツに階層構造を与え、ページの構成を理解しやすくします。支援技術は見出しをナビゲーションの目印として用いるため、見出し構造が適切であれば、ユーザーはいち早く目的の内容に到達できます。
見出しの階層
見出し階層のデモ
h1 から h6 までの標準的な見出し階層と、ARIA を用いたカスタム見出しの例です。見出しレベルは論理的な順序に従う必要があります。
Heading 1
Heading 2
Heading 3
Heading 4
Heading 5
Heading 6
Custom Heading (role="heading" aria-level="7")
ベストプラクティス:
- ページの主題には h1 を使用する
- 見出しレベルを飛ばさない(h1 の次に h3 としない)
- 先に見出しで論理的なアウトラインを作る
問題のある見出し
問題例: レベル飛び
❌ h2 や h3 を用いず h4 が現れるなど、誤った見出し階層の例です。論理的な文書構造が崩れます。
Main Title (h1)
Skipped to h4 - This is problematic!
この h4 は階層を保つため h2 にするべきです。
空の見出し
❌ テキストのない見出し要素です。支援技術のユーザーは、この見出しのついた部分に何があるのか予想できません。
この h6 要素にはテキストがなく、利用者に価値を提供しません。
画像
画像はスクリーンリーダーのような支援技術を使うユーザーにもアクセス可能である必要があります。以下では、適切な実装例とよくある間違いの双方を含む、画像アクセシビリティのさまざまな手法を示します。
<img> 要素
img 要素は、アクセシブルにするために適切な代替テキスト(alt)が必要です。
alt テキスト付きの画像
説明的な代替テキストを持つ適切な実装例です。これは画像をアクセシブルにする正しい方法です。
alt と title を併用した画像
alt と title の両方を指定した例です。title はツールチップとして表示されます。ツールチップを使った情報の提示は、ユーザーがその存在に気付けなかったり、そもそも表示できなかったりと問題がつきものです。
alt 属性のない画像
❌ alt が無いのは問題です。スクリーンリーダーはファイル名を読みあげたり、単に「画像」と読み上げたりして、意味のある内容が伝わりません。
title のみで alt が無い画像
❌ 代替テキストは alt 属性によって指定するべきです。
装飾目的で空の alt を持つ画像
⚠️ 空の alt はユーザーに伝えるべき情報がない画像であることを表現します。本当にユーザーに伝えるべき情報がないのかを、慎重に判断する必要があります。
空の alt と title を併用した装飾画像
空の alt で装飾画像としてマークしているため、支援技術が無視することがあります。ツールチップが表示されることで、マウスのユーザーにだけ情報が伝わる状況であり、不適切です。
aria-hidden を用いた画像
aria-hidden で支援技術から非表示にする方法です。装飾画像には空の alt の方が一般的です。
<svg> 要素
最近はしばしばアイコンなどに使用されています。SVG は title 要素、aria-label、role 属性などの手法でアクセシブルにできます。
title 要素を持つ SVG
️⚠️ ️title 要素によりスクリーンリーダーへアクセシブルネームを提供できます。標準的な手法ですが、一部のスクリーンリーダーやブラウザでのサポートが不十分な場合があります。role を img に設定する方が望ましいです。
title 要素と role=img を持つ SVG
✅ title 要素によりアクセシブルネームを提供し、role=img により画像として扱うことを明示しています。図形が画像であることが明確になります。
title 要素のない SVG
❌ 要素や属性による名前付けの無い SVG。これが図形であることすらスクリーンリーダーのユーザーにはわかりません。
aria-hidden を持つ SVG
支援技術から隠す装飾的な図形に使用します。ユーザーに情報を伝えない場合に適します。
aria-label を持つ SVG
⚠️ ️aria-label により title 要素を用いずにアクセシブルネームを提供できます。一部のスクリーンリーダーやブラウザでのサポートが不十分な場合があります。role を img に設定する方が望ましいです。
role=img と aria-label を持つ SVG
✅ 明示的に画像として扱い、aria-label で名前を提供します。図形が画像であることが明確になります。
role=presentation を持つ SVG
装飾として扱い、意味付けを取り除きます。
role="img"
img 以外の要素を画像として伝えるには role="img" を使用します。aria-label や aria-labelledby などでアクセシブルネームを付与しなければなりません。
role="img" と aria-label
✅ role='img' と説明的な aria-label の適切な使用例です。文字ベースのグラフィックや絵文字などに有用です。
role="img" かつ aria-label なし
❌ アクセシブルネームがありません。スクリーンリーダーは「画像」とだけ読み上げるかもしれせんし、テキストアート内の記号をそのまま読み上げるかもしれません。
リンク
リンクはページやセクション間を移動するための基本的なナビゲーション要素です。キーボード操作に対応し、支援技術に適切に伝わるよう実装する必要があります。
<a> 要素
href を持つ標準的なリンク
✅ href 属性を備えた適切なリンク。キーボードアクセスが可能で、支援技術にもナビゲーション要素として明確に伝わります。
href のない a 要素
❌ href のない a 要素は機能的なリンクではありません。JavaScript でリンク動作を実装していても、キーボードアクセスや支援技術への適切な伝達が行われません。
Link ロール
role="link" を持つ要素
⚠️ role="link" と tabindex="0" と JavaScript でリンクの機能を再現しようとしたもの。コンテキストメニュー(右クリックメニュー)などから「新しいタブで開く」操作ができないなど、リンクの実装としては不十分です。
リンクのバリエーション
target='_blank' のリンク
⚠️ 新しいウィンドウ/タブで開くリンク。強制的に新しいウィンドウ/タブが開くため、ユーザーの負担が増えることがあります。本当に必要なのかを検討してください。
アイコンリンク
アクセシブルネームを持たないアイコンによるリンク
❌ アクセシブルネームの無いアイコンだけのリンク。この状態ではスクリーンリーダーはURLの一部を読み上げたりすることがあり、ユーザーはリンク先や目的を理解できません。
テキストを伴うアイコンによるリンク
✅ アイコンと同じ意味をもつテキストによるニンク。アイコンの意味は装飾的であるため、aria-hidden='true' を付与しています。
ボタン
ボタンは操作を実行するためのインタラクティブ要素です。ボタンを押したら何が起きるのかという目的を、アクセシブルネームとして支援技術に伝えられなければなりません。キーボードによる操作への対応も必須です。以下は様々な実装例と、よくある問題点を示します。
<button> 要素
標準的な button 要素
✅ もっともアクセシブルな方法です。セマンティックな HTML の button はデフォルトでキーボード操作でき、支援技術にも適切に伝わります。
aria-hidden="true" を付けたボタン
❌ aria-hidden 属性によって支援技術はこのボタンを無視します。ところが視覚的には表示され、キーボードでも操作できます。支援技術のユーザーは操作方法によって見つけられないことがあります。
画像(alt あり)を含むボタン
✅ 適切な alt を持つ画像を含むボタンです。alt がそのままボタンのアクセシブルネームになります。
画像(alt なし)を含むボタン
❌ 画像に alt が無いため、このボタンの目的が支援技術に伝わりません。
Button ロール
div に role="button" と tabindex
⚠️ div 要素に role="button' と tabindex="0" を付与し、JavaScript でクリックイベントに加えてキーイベントも処理したもの。複雑な実装になってしまうため、 button 要素を使用するべきです。
role のない div ボタン
❌ role='button' が無いため、支援技術はインタラクティブ要素として認識できません。
tabindex のない div ボタン
❌ キーボードフォーカスを受けられないため、キーボード利用者は操作できません。
input 要素
input type="button"
✅ type='button' の input。value 属性に指定した値が表示され、アクセシブルネームとなります。
input type="button"(value 無し)
❌ value が無いため、アクセシブルネームがありません。何をするボタンか伝わりません。
input type="submit"
✅ フォーム送信用のボタン。value 属性に指定した値が表示され、アクセシブルネームとなります。
input type="submit"(value 無し)
明示的な value が無い例。「送信」や「Submit」などの規定の名前が付きますが、明示したほうが良いでしょう。
input type="reset"
✅ 入力内容をリセットするボタン。value 属性に指定した値が表示され、アクセシブルネームとなります。
input type="reset"(value 無し)
明示的な value が無い例。「リセット」や「Reset」などの規定の名前が付きますが、明示したほうが良いでしょう。
input type="image"(alt あり)
✅ type="image" の input 要素は画像ボタンになります。alt 属性に指定した値がアクセシブルネームとなります。
input type="image"
❌ alt のない画像ボタン。支援技術は何の目的のボタンなのかをユーザーに伝えられません。
summary 要素
summary 要素
✅ details と組み合わせて開閉 UI を作るための要素。セマンティックに正しく、アクセシブルです。
Click Me
Details content revealed when summary is clicked.
summary 要素のない details
summary 要素が無い場合、ブラウザは「詳細」のようなデフォルトのラベルを表示します。
Details content revealed when summary is clicked.
details 外の summary
❌ details の外で summary を使うのは正しくありません。
アクセシブルネームのない summary
❌ テキストやアクセシブルネームが無いため、何の操作か分かりません。
Details content that can't be properly accessed.
フォームコントロール
フォームコントロールは入力のためのインタラクティブ要素です。適切なラベル付けと、キーボード・支援技術への対応が必要です。以下は良い実装とよくある問題の両方を示します。
テキスト入力
ラベルのない input
❌ 支援技術は、フィールドの目的をフィールドから辿ってユーザーに提示することができません。
適切なラベル付き input
✅ for と id を用いて関連付けた例。ラベルと入力のプログラム上の関係を構築します。
label 内に含まれる input
✅ label 要素内に input を含める方法もあります。for/id の関連付けと同様に機能します。
select 要素
ラベルのない select
❌ このセレクトボックスの目的が分かりません。
適切なラベル付き select
✅ ラベルと関連付けられており、支援技術はセレクトボックスの目的と選択肢をユーザーに伝えられます。
textarea 要素
ラベルのない textarea
❌ 何を入力すべきか分かりません。
適切なラベル付き textarea
✅ 支援技術のユーザーに対しても、テキストエリアの目的を明確に伝えられます。
チェックボックス
ラベル付きのチェックボックス
✅ 各チェックボックスに明確な名前があり、支援技術もそれらを認識します。
ラベルのないチェックボックス
❌ 近くにテキストがあっても、プログラム上の関連付けがありません。スクリーンリーサーのユーザーは、どのチェックボックスが何を意味するのか分かりづらくなります。
display: none を使うカスタムチェックボックス
❌ display: none により、キーボードや支援技術から到達できません。
ラジオボタン
ラベル付きのラジオボタン
✅ 同一の name 属性をつけることで、ブラウザや支援技術が解釈できるかたちでラジオボタンをグループ化しています。それぞれの選択肢は label 要素により名前がつけられています。 fieldset 要素 と legend 要素で、グループ全体のラベルもつけられています。
ラベルのないラジオボタン
❌ 視覚的にテキストがあっても、プログラム上の関連付けが無くアクセシブルではありません。
name のないラジオボタン
❌ グループを形成できず、同時に複数選択できてしまいます。
異なる name を持つラジオボタン
❌ グループにならず、独立したボタンとして扱われます。
単体で置かれたラジオボタン
❌ 選択肢が1つだけのときは、ラジオボタンではなくチェックボックスを使うべきです。ユーザーはラジオボタンのチェック状態を解除できません。
ラベルの問題
孤立した label
⚠️ どのフォームコントロールにも関連付かず、意味がありません。
存在しない ID を参照する label
⚠️ 対応する入力が存在していません。指定する ID を間違えていませんか?
The input with id="non-existent-input" doesn't exist in the document.
入力の状態
必須の入力
✅ required 属性により必須であることを伝えます。視覚的な指標やエラーメッセージも併用しましょう。
読み取り専用の入力
ユーザーが変更できない入力。スクリーンリーダーは状態を読み上げます。固定情報の表示に有用です。
contenteditable 属性
role のない contenteditable
⚠️ 動作はしますが、スクリーンリーダーがテキスト入力として認識しない場合があります。
role='textbox'+aria-labelledby の contenteditable
✅ textbox ロールとラベル関連付けにより、アクセシブルな編集領域になります。
ラベルのない contenteditable
❌ ラベルやアクセシブルネームがなく、用途が分かりません。
レイアウトとランドマーク
セマンティックな HTML 要素や ARIA ランドマークは、ページ構造の理解と効率的な移動に役立ちます。これらはコンテンツ各所の文脈を提供します。
セマンティックなセクション
ランドマーク要素
✅ ランドマーク要素を適切に用い、ページに明確な構造と意味を与えます。
<header> - Page or section header <main> - Main content area
ARIA ランドマーク
ARIA のランドマークロール
✅ セマンティック HTML と同様のナビゲーション上の利点を提供します。セマンティック HTML が使えないときに利用します。
role="banner" - Equivalent to <header>role="main" - Equivalent to <main>role="complementary" - Equivalent to <aside>role="contentinfo" - Equivalent to <footer>
汎用コンテナー
セマンティックな意味のない div コンテナー
❌ ページの主要セクションを div だけで構成すると、支援技術に意味が伝わりません。
これらの div は目的や構造に関する情報を提供しません。
section 要素
アクセシブルネームをつけた section
section 要素にアクセシブルネームをつけると region ロールとなり、ランドマークとして機能します
About Our Services
この section は見出しの id 属性値を section 要素の aria-labelledby 属性で参照しています。
アクセシブルネームのない section
アクセシブルネームの提供されていない section 要素はランドマークとして機能しません。
About Our Services
この section は見出しをただ置いただけの状態です。iFrame 要素
title を持つ iFrame
✅ 内容を説明する title を持つ iFrame。フレーム内容の理解に必須です。
title の無い iFrame
❌ title が無く、フレーム内容を支援技術が把握できません。
ダイアログとモーダル
dialog 要素
HTML の dialog 要素の例。showModal() で開くとフォーカスを閉じ込め、背後の操作をブロックします。
aria-modal='true' を持つ要素
✅ 適切なフォーカス管理を伴うカスタムモーダル。モーダル内にフォーカスを閉じ込め、閉じると開いたボタンに戻します。
テーブル
テーブルは行と列でデータを整理します。支援技術がデータの関係を理解できるよう、適切な構造が必要です。
テーブルの構造
適切なヘッダーを持つテーブル
✅ th 要素と scope 属性を用いた適切な構造。スクリーンリーダーが列・行の関係を認識できます。
| Name | Age | City |
|---|---|---|
| John | 25 | New York |
| Jane | 30 | London |
ヘッダーのないテーブル
❌ th を用いず td だけで構成されたテーブル。支援技術がデータの関係を把握できません。
| Name | Age | City |
| John | 25 | New York |
| Jane | 30 | London |
行見出しのあるテーブル
✅ 列見出しに加えて行見出しも備え、複雑なデータ関係を scope 属性で表現しています。
| Quarter | Sales | Profit |
|---|---|---|
| Q1 | $100K | $20K |
| Q2 | $150K | $30K |
caption のあるテーブル
✅ caption 要素によりテーブルの目的や内容の文脈を提供します。利用者が理解しやすくなります。
| Name | Department |
|---|---|
| Alice | Engineering |
| Bob | Marketing |
ARIA hidden
aria-hidden 属性は要素を支援技術に公開するかどうかを制御します。適切に使えば装飾的な内容を隠せますが、誤用すると重要な情報がアクセス不能になります。
可視コンテンツ
aria-hidden="false" の可視テキスト
可視かつ支援技術に公開されるテキスト。要素は公開されているのがデフォルトで、 aria-hidden 属性を指定する必要はありません。
このテキストは視覚的に見えていて、スクリーンリーダーでも読むことができます。
aria-hidden="true" の可視テキスト
❌ 視覚的には見えるのに支援技術からはアクセスできません。スクリーンリーダー利用者には内容が伝わりません。
アイコン
aria-hidden="true" の装飾アイコン
✅ 重要な情報を伝えない装飾アイコンに aria-hidden を使う適切な例。アイコンは隠され、テキストは引き続きアクセス可能です。
aria-hidden を付けない重要なアイコン
❌ アイコンで表現された情報が、支援技術向けに伝わる状態になっていません。
適切にラベル付けされたアイコン
✅ aria-label で意味を提供する例。視覚的にはアイコンで、支援技術へは aria-label で情報を伝えます。
ライブリージョン
ライブリージョンは動的な内容の変化を支援技術に伝えます。状態更新やエラーなど、即時に把握すべき情報の通知に不可欠です。
aria-live 属性
aria-live="polite"
ユーザーの操作を妨げないタイミングで案内するライブリージョン。緊急性の低いステータス更新に適します。
aria-live="assertive"
変更を即座に通知し、スクリーンリーダーの読み上げを割り込みます。重要な警告やエラーに使用します。
ライブリージョンのロール
role="status"
重要度の低い案内情報を伝えるロール。aria-live="polite" と似た挙動です。
role="alert"
時間に敏感な重要情報を伝えるロール。aria-live="assertive" と似た挙動です。
output 要素
<output> 要素
計算結果やフォームの出力を表示する要素。暗黙的にライブリージョンの挙動があります。
aria-atomic 属性
aria-atomic="true" のライブリージョン
内容の一部が変化した場合でも、領域全体が読み上げられます。
問題のあるライブリージョン
ライブリージョンでない動的コンテンツ
動的に変化してもライブリージョンとしてマークされていないため、支援技術に変化が伝わりません。
Screen readers won't announce the time update because this isn't a live region.
優先度の相互作用
polite と assertive の同時更新
assertive が polite を割り込む挙動を示します。同時更新時、polite の読み上げは抑制される場合があります。
Polite (should be announced)
Assertive (will interrupt)
Test behavior: Click "Update Both Simultaneously" and observe that the polite region's announcement may be suppressed by the assertive region. The Accessibility Visualizer extension shows this behavior by only displaying the assertive announcement when both regions update at the same time.
優先度の異なる順次更新
assertive の通知が、キューにある polite の未読を打ち消す場合があることを示します。
Polite announcements
Assertive interruptions
Test behavior: Start the polite sequence to see 8 polite messages being displayed sequentially. Then click "Interrupt with Assertive" - the assertive message will be triggered after 3 seconds to avoid focusin clearing the live region display. Observe how the assertive announcement interrupts and clears the remaining polite messages.
aria-busy の抑止
aria-busy による抑止
aria-busy="true" が設定された間はライブリージョンの通知が抑制されます。内容は変化しても読み上げられません。
Live region (will be suppressed when busy)
aria-busy status:
false
Test behavior: Click "Update Content" to see normal live region announcements. Then click "Toggle aria-busy" to mark the region as busy, and try "Update Content" again - the content will change but no announcement will be made. The Accessibility Visualizer extension respects aria-busy and will not display announcements for busy regions.
継続的に更新されるライブリージョン
polite のタイマー通知
1 秒ごとに更新する polite なライブリージョン。頻繁な更新時の挙動テストに有用です。
assertive のカウンター通知
2 秒ごとに自動インクリメントする assertive なライブリージョン。割り込みの頻度が高いケースのテストに有用です。
role="status" によるステータス更新
3 秒ごとに更新されるステータスメッセージ。ロールベースのライブリージョンに対する継続更新の扱いをテストします。