display: none、visibility: hidden、aria-hidden のアクセシビリティへの影響と適切な使い分け
ウェブサイトやウェブアプリケーションを開発する上で、要素を一時的あるいは永続的に画面から非表示にしたい場面は多く存在します。例えば、タブパネルの非アクティブなコンテンツ、モーダルダイアログが開いている際の背景要素、一時的なメッセージ表示領域などが挙げられます。これらの要素を非表示にする方法として、CSSの display: none;
や visibility: hidden;
、そしてARIA属性の aria-hidden="true"
などが一般的に使用されます。
しかし、これらの非表示方法は視覚的な表示だけでなく、アクセシビリティツール(特にスクリーンリーダー)による要素の認識や操作性にも異なる影響を与えます。適切な方法を選択しないと、コンテンツがスクリーンリーダー利用者にとって利用できなくなったり、逆に不要な情報を読み上げてしまったりといった問題が発生します。
本記事では、display: none;
、visibility: hidden;
、aria-hidden="true"
がそれぞれアクセシビリティにどのような影響を与えるかを解説し、それぞれの特徴を踏まえた適切な使い分けの方法について、具体的なコード例を交えて説明します。
なぜ非表示の方法によってアクセシビリティが変わるのか
要素の非表示方法がアクセシビリティに影響するのは、それぞれの方法がブラウザのレンダリングプロセスや、アクセシビリティツリーの構築に異なる作用を及ぼすためです。
- レンダリングツリーとアクセシビリティツリー: ブラウザはHTMLを解析してDOMツリーを構築し、CSSを適用してレンダリングツリー(視覚的な表現を決定するツリー)を構築します。これとは別に、支援技術がWebページの構造やコンテンツを理解するために利用するのがアクセシビリティツリーです。アクセシビリティツリーはDOMツリーを元に構築されますが、すべてのDOM要素がアクセシビリティツリーに含まれるわけではありません。非表示の方法によっては、要素がレンダリングツリーから除外されたり、アクセシビリティツリーから除外されたりします。
スクリーンリーダーは、主にこのアクセシビリティツリーを読み取って利用者に情報を提供します。したがって、アクセシビリティツリーに含まれるかどうかが、スクリーンリーダー利用者にとってその要素が存在するかどうかに直結します。
display: none; の特徴とアクセシビリティ
display: none;
は、指定された要素とそのすべての子孫要素を、レンダリングツリーから完全に削除します。
実装例
.hidden-display {
display: none;
}
<div class="hidden-display">
<p>このコンテンツは完全に非表示になります。</p>
<a href="#">このリンクもアクセスできません。</a>
</div>
アクセシビリティへの影響
display: none;
が適用された要素は、レンダリングツリーから除外されるだけでなく、多くの場合、アクセシビリティツリーからも除外されます。
- 視覚: 要素は完全に表示されず、スペースも占有しません。
- スクリーンリーダー: 要素とその子孫は読み上げられません。
- キーボード操作: 要素内のインタラクティブ要素(リンク、ボタンなど)にフォーカスが移動することはありません。
適切な使用例
- ページロード時には表示されないが、JavaScriptなどで動的に表示/非表示を切り替える要素(例:ドロップダウンメニューの内容、モーダルダイアログ自体)。
- 完全に不要になった要素や、視覚的にも支援技術に対しても隠したい要素。
visibility: hidden; の特徴とアクセシビリティ
visibility: hidden;
は、要素を視覚的に非表示にしますが、その要素が本来占めるべきスペースは確保されたままになります。
実装例
.hidden-visibility {
visibility: hidden;
}
<div class="hidden-visibility" style="border: 1px solid red;">
<p>このコンテンツは視覚的に非表示ですが、スペースは確保されます。</p>
<button>このボタンはhiddenですが、Tabキーでフォーカスされる場合があります(ブラウザによる)</button>
</div>
アクセシビリティへの影響
visibility: hidden;
が適用された要素は視覚的には非表示ですが、アクセシビリティツリーには通常残ります。
- 視覚: 要素は表示されず、透明になりますが、レイアウト上のスペースは保持されます。
- スクリーンリーダー: 要素の内容は通常読み上げられます。これはしばしば意図しない挙動となります。
- キーボード操作: ブラウザの実装にもよりますが、
visibility: hidden;
の要素内のインタラクティブ要素にキーボードフォーカスが移動してしまう場合があります。これはキーボード利用者を混乱させる可能性があります。
適切な使用例
visibility: hidden;
はアクセシビリティの観点から見て、要素を完全に隠したい場合には推奨されません。視覚的には非表示にしつつ、スクリーンリーダーには読み上げさせたいという特殊なケース(非常に稀です)以外では、display: none;
または aria-hidden="true"
の使用を検討すべきです。
aria-hidden="true" の特徴とアクセシビリティ
aria-hidden="true"
は、要素をアクセシビリティツリーから除外します。視覚的な表示には一切影響しません。
実装例
<div>
<img src="icon.png" alt="設定" aria-hidden="true">
<button>設定</button> <!-- 画像は単なる装飾なのでaria-hiddenで隠し、ボタンテキストで意味を伝える -->
</div>
<div aria-hidden="true">
<!-- このdiv内のすべてのコンテンツ(画像、テキスト、リンクなど)はスクリーンリーダーから隠される -->
<p>このテキストはスクリーンリーダーには読み上げられません。</p>
<a href="#">このリンクもスクリーンリーダーからはアクセスできません。</a>
</div>
アクセシビリティへの影響
aria-hidden="true"
が適用された要素は、アクセシビリティツリーから除外されます。
- 視覚: 要素は通常通り表示されます。
- スクリーンリーダー: 要素とその子孫は読み上げられません。
- キーボード操作: 要素内のインタラクティブ要素へのキーボードフォーカスは妨げられません。これが
aria-hidden="true"
を使う上での重要な注意点です。aria-hidden="true"
を適用した要素内にインタラクティブ要素を含めるべきではありません。視覚的には要素が見えているのに、キーボードでフォーカスできず、スクリーンリーダーには存在が知らされないという、利用者を混乱させる状況を招きます。
適切な使用例
- 装飾的な要素: アイコンや背景画像など、コンテンツの意味を伝える上で重要ではない視覚的な要素。
- 画面上に表示されているが、スクリーンリーダー利用者にとっては冗長または混乱を招く要素: 例えば、メインコンテンツと重複する情報の繰り返しや、視覚的なレイアウトのためだけに存在する要素。
- オフスクリーンに配置されているが、JavaScriptで動的に表示されるわけではない要素: 例外的なケースですが、CSSで画面外に配置しつつ、スクリーンリーダーからも隠したい場合に利用されることがあります。
適切な使い分けのガイドライン
これらの違いを踏まえると、以下のような使い分けが推奨されます。
-
要素を視覚的にも完全に非表示にし、スペースも占有させず、スクリーンリーダーからも隠したい場合:
display: none;
を使用します。要素がレンダリングツリーとアクセシビリティツリーの両方から除外されるため、最もクリーンな方法です。動的なコンテンツの表示/非表示切り替えに広く使われます。
-
要素を視覚的には表示したまま、スクリーンリーダーからのみ隠したい場合:
aria-hidden="true"
を使用します。ただし、この要素内にインタラクティブ要素(リンク、ボタン、フォーム部品など)を含めないように細心の注意が必要です。含めてしまうと、キーボード操作でフォーカスできるのにスクリーンリーダーが読み上げないという問題が発生します。装飾的なアイコンなど、インタラクティブでない要素に主に適用します。
-
要素を視覚的に非表示にしたいが、アクセシビリティツリーには残したい場合:
- これは非常に稀なケースであり、通常は推奨されません。
visibility: hidden;
はアクセシビリティツリーに残るためスクリーンリーダーに読み上げられてしまう可能性が高く、キーボードフォーカスも問題となるため、要素を完全に隠す目的では避けるべきです。
- これは非常に稀なケースであり、通常は推奨されません。
-
要素を視覚的には非表示にしつつ、スクリーンリーダーには読み上げさせたい場合(オフスクリーンテキストなど):
- これは通常、要素を画面外の表示領域(オフスクリーン)にCSSで配置することで実現します。視覚的には見えませんが、DOM上には存在し、アクセシビリティツリーにも含まれるため、スクリーンリーダーが読み上げることができます。特定の目的(例:アイコンボタンにテキストラベルを付けるが、アイコンだけ表示したい場合)で使用されます。これは
display: none;
,visibility: hidden;
,aria-hidden="true"
とは異なるテクニックです。
css .visually-hidden { position: absolute; width: 1px; height: 1px; margin: -1px; border: 0; padding: 0; clip: rect(0, 0, 0, 0); /* older browsers */ clip-path: inset(50%); /* current browsers */ overflow: hidden; white-space: nowrap; }
このクラスは、要素を視覚的には隠しつつ、スクリーンリーダーが内容を読み取れるようにするための標準的な手法です。 - これは通常、要素を画面外の表示領域(オフスクリーン)にCSSで配置することで実現します。視覚的には見えませんが、DOM上には存在し、アクセシビリティツリーにも含まれるため、スクリーンリーダーが読み上げることができます。特定の目的(例:アイコンボタンにテキストラベルを付けるが、アイコンだけ表示したい場合)で使用されます。これは
実装時の注意点
- インタラクティブ要素への
aria-hidden="true"
: 繰り返しになりますが、aria-hidden="true"
をインタラクティブ要素(リンク、ボタン、フォーム部品、tabindex="0"
が付与された要素など)を含む要素に適用しないでください。 - 動的な変更: JavaScriptで要素の表示/非表示を切り替える際、単にCSSクラスを付け外しするだけでなく、アクセシビリティツリーへの影響も考慮して適切なプロパティや属性(
display: none
またはaria-hidden="true"
)を選択してください。 - 親要素への適用:
display: none;
やvisibility: hidden;
は子孫要素にも影響しますが、aria-hidden="true"
も同様に子孫要素にも影響します。親要素にaria-hidden="true"
をつけると、その中のすべての要素がスクリーンリーダーから隠されます。
テスト方法
実装した非表示の方法が期待通りに機能しているかを確認するには、以下の方法を試してください。
- スクリーンリーダーでの確認: 実際に主要なスクリーンリーダー(NVDA, JAWS for Windows, VoiceOver for macOS/iOS, TalkBack for Androidなど)を使用して、非表示にした要素の内容が読み上げられないこと、または意図通りに読み上げられることを確認します。特に、キーボード(Tabキーなど)で操作し、非表示にしたはずの要素にフォーカスが移動しないか確認してください。
- アクセシビリティ評価ツール: ブラウザのDeveloper Toolsに内蔵されているアクセシビリティツリービューアや、Web Accessibility Evaluation Tool (WAVE), axe DevToolsなどのツールを使用して、非表示にした要素がアクセシビリティツリーに含まれているか、あるいは除外されているかを確認します。
まとめ
要素を非表示にする方法は複数あり、それぞれアクセシビリティに与える影響が異なります。
display: none;
: 視覚的にもアクセシビリティツリーからも完全に削除したい場合に最適です。動的なコンテンツの表示/非表示に広く使われます。visibility: hidden;
: 視覚的に非表示ですが、アクセシビリティツリーには残るため、通常は非表示の目的で推奨されません。aria-hidden="true"
: 視覚的な表示はそのままに、アクセシビリティツリーからのみ削除したい場合に用います。ただし、インタラクティブ要素には絶対に使用しないでください。主に装飾要素や冗長なコンテンツを隠すために使われます。- オフスクリーン配置 (
.visually-hidden
クラスなど): 視覚的には隠しつつ、スクリーンリーダーには内容を読み上げさせたい場合に用いる標準的なテクニックです。
これらの違いを理解し、それぞれの状況に応じて適切な方法を選択することで、視覚的なデザインとアクセシビリティの両立を図ることができます。実装後は必ず、スクリーンリーダーなどでのテストを行い、意図通りに動作することを確認してください。