第21章 アクセシビリティ
21.1 ユーティリティと a11y の関係
アクセシビリティ(a11y)は、障害の有無や利用環境にかかわらず、誰もが使える Web を作るための取り組みです。ここで最初に押さえるべき大原則があります。
クラスは「見た目」、意味は「HTML」が担う。
Tailwind のユーティリティは見た目を整えるだけで、要素の意味は HTML が決めます。<div class="..."> をボタンのように装飾しても、スクリーンリーダーにはボタンとして伝わりません。ボタンは <button>、見出しは <h1>〜<h6>、ナビゲーションは <nav> を使う——この「正しい HTML を書く」ことが、アクセシビリティの土台です。Tailwind を使っても、この原則は何も変わりません。むしろ「クラスで見た目を作れてしまう」からこそ、正しい要素を選ぶ意識が大切です。
21.2 視覚的に隠す sr-only
「目には見せないが、スクリーンリーダーには読ませたい」テキストがあります。たとえばアイコンだけのボタンには、見た目上はラベルが要りませんが、スクリーンリーダー利用者には何のボタンか伝える必要があります。
このための専用ユーティリティが sr-only です。
<button>
<svg><!-- 検索アイコン --></svg>
<span class="sr-only">検索</span>
</button>
sr-only は、要素を視覚的に消しつつ(display: none とは違い)支援技術には読み上げさせる、という CSS を当てます(実体は position: absolute; width: 1px; height: 1px; overflow: hidden; ... といった定番のテクニックです)。display: none だと読み上げからも消えてしまうので、この使い分けが重要です。逆に「狭い画面では隠し、広い画面では見せる」には sr-only sm:not-sr-only のように not-sr-only で打ち消します。
21.3 フォーカス可視化(focus-visible とリング)
キーボードだけで操作する人にとって、「いまどこにフォーカスがあるか」が見えることは死活問題です。ところがデザインの都合で、ブラウザ標準のフォーカス枠を outline-none で消してしまう例が後を絶ちません。フォーカスの可視化を消すなら、必ず代わりを用意するのが鉄則です。
ここで役立つのが第6章の focus-visible: です。これは CSS の :focus-visible に対応するもので、ブラウザが「フォーカス表示を出すべきだ」と判断したときだけスタイルを当てます。ブラウザは入力方式(マウスかキーボードか)や要素の種類から自動でこれを判断します。たとえばボタンの場合、キーボード操作でフォーカスしたときには枠が出て、マウスでクリックしただけのときには出ない、という具合です。これにより、マウス利用者には余計な枠を出さず、キーボード利用者にはしっかり枠を見せられます。
ただし「マウスでは絶対に出ない」と言い切れるわけではありません。テキスト入力欄のように、クリックでフォーカスしても表示が必要とブラウザが判断する要素では、マウス操作でも枠が出ることがあります。挙動はブラウザと要素任せで、こちらが細かく制御するものではない、と理解しておくとよいでしょう。
<button class="focus:outline-none focus-visible:ring-2 focus-visible:ring-blue-500">
キーボード操作のときだけリングが出る
</button>
21.4 aria-* / data-* バリアントで状態を見た目に反映
トグルボタンやアコーディオンのような UI では、「押されている」「開いている」といった状態を、見た目とスクリーンリーダーの両方に伝える必要があります。状態は ARIA 属性(aria-pressed・aria-expanded など)で表現し、第6章の aria-* バリアントでその見た目を作ります。
<button aria-pressed="true" class="aria-pressed:bg-blue-600 aria-pressed:text-white">
トグル
</button>
aria-pressed 属性を切り替えれば、見た目(aria-pressed: のスタイル)も支援技術への伝達も同時に正しくなります。「見た目だけ変えて ARIA 属性を更新し忘れる」というありがちなバグを、属性ドリブンにすることで防げます。
21.5 コントラスト・色だけに依存しない設計
色に関するアクセシビリティで重要な点が 2 つあります。
- コントラスト比を確保する: 文字と背景のコントラストが低いと、弱視の人や明るい屋外では読めません。
text-gray-400を白背景に置くような薄い文字は要注意です。目安は WCAG の AA 基準で、通常テキストは 4.5:1 以上です(大きな文字は 3:1 以上など、一部に例外があります)。この基準を満たす配色を選びます。 - 色だけで情報を伝えない: 「赤が必須、緑が任意」のように色だけで区別すると、色覚特性のある人に伝わりません。色に加えて、アイコンやテキスト(「※必須」など)を併用します。エラーを赤くするだけでなく、エラーメッセージの文言も添える、という具合です。
第19章で扱った motion-reduce: への配慮も、アクセシビリティの一環です。装飾的なアニメーションには動きを止める手段をセットにします。
21.6 実務: キーボード操作と Headless UI の活用
複雑な UI(モーダル、ドロップダウン、タブ、コンボボックスなど)を正しくアクセシブルに作るのは、実はとても難しいことです。フォーカスの管理(モーダルの外にフォーカスが出ないようにする)、キーボード操作(矢印キーでメニューを移動、Esc で閉じる)、適切な ARIA 属性——これらを自前で完璧に実装するのは大変です。
ここで頼れるのが、Tailwind Labs 製の Headless UI です。これは「スタイルを持たないが、アクセシビリティと操作性は作り込まれている」UI 部品集です。見た目は持たないので、Tailwind のユーティリティで自由に装飾できます。「面倒で間違えやすいアクセシビリティの部分はライブラリに任せ、見た目は Tailwind で作る」という、理想的な分担ができます(React での活用は第25章で扱います)。
第5部はここまでです。レスポンシブ・ダークモード・アニメーション・フォーム・アクセシビリティという、実プロダクトで必ず問われるテーマを、すべて第2部のバリアントの応用として見てきました。次の第6部では、ここまで何度も「コンポーネント化で解決する」と先送りにしてきた話題——長いクラス列をどう再利用可能な部品にまとめるか——に正面から取り組みます。