CSSだけでできるアクセシビリティ改善3選【やりがちなミスも解説】
前回の記事ではクリッカブルエリアの調整とprefers-reduced-motionを利用したアニメーションの制御について紹介しました。
今回はその続編として、CSSを用いたアクセシビリティ対応のポイントをさらに3つ紹介します。
:focus-visibleを使ったフォーカスインジケーターのカスタマイズ
キーボードでwebサイトを操作した時に、今どの要素にフォーカスが当たっているかわからなくなった経験はありませんか?
フォーカスインジケーター(フォーカスリング)は、キーボード操作をするユーザーにとって「今どこにいるか」を示す重要な視覚的手がかりです。
詳しくは以下の「Web Content Accessibility Guidelines (WCAG)」を参照してください。
outline: noneの落とし穴
CSSリセットなどで以下のようなコードを見たことはありませんか?
*:focus {
outline: none;
}
この記述はフォーカスインジケーターを完全に消してしまうため、キーボードユーザーがどの要素にフォーカスしているかわからなくなってしまいます。
WCAG 2.4.7「Focus Visible(レベルAA)」では、キーボード操作可能なUIにはフォーカスインジケーターが見える状態であることが求められています。
そのため、outline: noneを使う場合は必ず代替のフォーカススタイルをセットで定義するようにしましょう。
:focusと:focus-visibleの違い
:focusはマウスクリック時にもフォーカススタイルが表示されますが、:focus-visibleはブラウザが「フォーカスインジケーターの表示が必要」と判断した場合にのみ適用されます。
具体的にはキーボード操作でフォーカスした時にスタイルが当たり、マウスクリック時には当たらないという挙動になります。
これにより「マウスクリックした時にoutlineが表示されて見た目が気になる」という問題を解決しつつ、キーボードユーザーにはしっかりフォーカスを表示することができます。
対応方法について
:focus-visibleを利用してフォーカスインジケーターをカスタマイズするコードは以下になります。
<a class="link" href="#">リンク1</a>
<button class="button" type="button">ボタン1</button>
/* マウスクリック時のoutlineを非表示にする */
.link:focus:not(:focus-visible),
.button:focus:not(:focus-visible) {
outline: none;
}
/* キーボード操作時のフォーカススタイル */
.link:focus-visible,
.button:focus-visible {
outline: 2px solid #1a73e8;
outline-offset: 2px;
border-radius: 2px;
}
ポイントとしては以下になります。
-
:focus:not(:focus-visible)でマウスクリック時のoutlineを非表示にする。 -
:focus-visibleでキーボード操作時のみフォーカススタイルを適用する。 -
outline-offsetでoutlineと要素の間に余白を持たせることで視認性を向上させる。 - フォーカスインジケーターのコントラスト比は3:1以上にすることが推奨されています(WCAG 2.2 SC 2.4.13 Focus Appearance)。
DevToolsでフォーカス状態を確認する方法
実際にキーボードで操作しなくても、ブラウザのDevToolsでフォーカス状態を確認することができます。
- DevToolsを開く(
F12orCmd + Option + I) - 確認したい要素を選択
- 「Styles」パネルの
:hovボタンをクリック -
:focus-visibleにチェックを入れる

これでフォーカス状態のスタイルを手軽に確認することができます。
カラーコントラストを意識する
テキストと背景の色の組み合わせによっては、色覚特性のあるユーザーや視力の弱いユーザーがテキストを読みにくくなってしまう ことがあります。
デザイン上おしゃれな薄いグレーのテキストも、アクセシビリティ的には問題になるケースがあります。
CSSで色を定義する際に、十分なコントラスト比を確保 することが大切です。
詳しくは以下の「Web Content Accessibility Guidelines (WCAG)」を参照してください。
WCAGで求められるコントラスト比について
WCAGでは以下のコントラスト比が求められています。
| テキストの種類 | 最低限(AA) | より高い基準(AAA) |
|---|---|---|
| 通常テキスト | 4.5:1 | 7:1 |
| 大きいテキスト(24px以上 / Bold 18.66px以上) | 3:1 | 4.5:1 |
対応方法について
コントラスト比が低い例と十分な例のコードは以下になります。
/* ❌ コントラスト比が低い例(約2.6:1) */
.text-low-contrast {
color: #999999;
background-color: #ffffff;
}
/* ✅ コントラスト比が十分な例(約8.6:1) */
.text-high-contrast {
color: #333333;
background-color: #ffffff;
}
またprefers-color-scheme を利用してダークモードに対応する場合も、ライトモード・ダークモードそれぞれでコントラスト比を確認するようにしましょう!
/* ダークモード対応の例 */
:root {
--color-text: #333333;
--color-background: #ffffff;
}
@media (prefers-color-scheme: dark) {
:root {
--color-text: #e5e5e5;
--color-background: #1a1a1a;
}
}
コントラスト比を確認したい時に
以下のツールで簡単にコントラスト比を確認できます。
webサイトで確認する
Chrome DevTools を利用して確認する
以下の手順で確認を行うことができます。
- DevTools を開く(
F12またはCmd + Option + I) - Elements タブ左上の矢印アイコン(インスペクターボタン)をクリック
- ページ上の確認したいテキスト要素にカーソルを合わせる
- ツールチップにコントラスト比が表示される(問題がある場合は ⚠️ マークつき)

visually-hiddenパターンでスクリーンリーダーに情報を提供する
アイコンのみのボタンやデザイン上テキストを省略している箇所で「このボタン何だろう?」と思ったことはありませんか?
見た目にはわかっていても、スクリーンリーダーを利用しているユーザーにはその意味が伝わらないことがあります。
そのような場合に、見た目には隠しつつスクリーンリーダーには読み上げられるテキストを追加するvisually-hiddenパターンが有効です。
display: noneやvisibility: hiddenではダメな理由
/* これらはスクリーンリーダーからも隠れてしまう */
.hidden-1 {
display: none;
}
.hidden-2 {
visibility: hidden;
}
display: noneやvisibility: hiddenを利用してしまうと、スクリーンリーダーからもコンテンツが見えなくなってしまうため、必要な情報を読み上げてもらうことができません。
visually-hiddenクラスの実装
見た目には隠しつつ、スクリーンリーダーからはアクセス可能にするCSSパターンは以下になります。
.visually-hidden {
clip: rect(0 0 0 0);
clip-path: inset(50%);
height: 1px;
overflow: hidden;
position: absolute;
white-space: nowrap;
width: 1px;
}
各プロパティの役割について解説します。
clip: rect(0 0 0 0) / clip-path: inset(50%)
要素の可視領域をゼロにクリッピングします。
clipは現在**非推奨(Deprecated)**となっており、clip-pathが後継の標準プロパティです。
レガシーブラウザをサポートする必要がない場合はclip-pathのみでも問題ありません。
height: 1px / width: 1px
要素のサイズを1pxに設定します。
0pxに設定すると一部のブラウザでアクセシビリティツリーから除外される可能性があるため、1pxにしています。
overflow: hidden
1pxの領域からはみ出すコンテンツを非表示にします。
position: absolute
要素を通常のレイアウトフローから外して、他の要素のレイアウトに影響を与えないようにします。
white-space: nowrap
テキストの折り返しを防止します。
スクリーンリーダーのビジュアルトラッキング(読み上げ位置を視覚的に示す機能)が正しく動作するために必要です。
利用例1: アイコンのみのボタン
<button class="icon-button" type="button">
<svg aria-hidden="true" width="24" height="24" viewBox="0 0 24 24">
<!-- ハンバーガーメニューのアイコン -->
<path d="M3 18h18v-2H3v2zm0-5h18v-2H3v2zm0-7v2h18V6H3z" />
</svg>
<span class="visually-hidden">メニューを開く</span>
</button>
ポイントとしては以下になります。
- SVGには
aria-hidden="true"を追加してスクリーンリーダーからアイコン自体を隠す。 -
visually-hiddenクラスを利用したspanでボタンの意味をスクリーンリーダーに伝える。 - スクリーンリーダーは「メニューを開く、ボタン」と読み上げる。
利用例2: 「もっと見る」リンクの補足
一覧ページなどで「もっと見る」というリンクが複数あると、スクリーンリーダーではすべてが同じ「もっと見る」として読み上げられてしまい、どの「もっと見る」なのかが区別できません。
<a href="/news">
もっと見る<span class="visually-hidden">(ニュース一覧)</span>
</a>
<a href="/blog">
もっと見る<span class="visually-hidden">(ブログ一覧)</span>
</a>
これにより、スクリーンリーダーでは「もっと見る(ニュース一覧)、リンク」のように読み上げてくれるため、どのリンクなのかを区別することができます。
利用例3: スキップリンク
ページの先頭にあるナビゲーションをスキップして、メインコンテンツに直接移動するための「スキップリンク」にも活用できます。
通常は非表示ですが、Tabキーでフォーカスが当たった時に表示されるようにします。
<a class="skip-link" href="#main-content">メインコンテンツへスキップ</a>
.skip-link {
clip: rect(0 0 0 0);
clip-path: inset(50%);
height: 1px;
overflow: hidden;
position: absolute;
white-space: nowrap;
width: 1px;
}
.skip-link:focus {
clip: auto;
clip-path: none;
height: auto;
overflow: visible;
position: fixed;
top: 8px;
left: 8px;
width: auto;
z-index: 9999;
padding: 8px 16px;
background: #000;
color: #fff;
font-size: 14px;
border-radius: 4px;
}
フォーカスを受け取った時にclipやclip-pathをリセットすることで、視覚的にもリンクが表示されるようになります。
CSSフレームワークでの対応
代表的なCSSフレームワークでは、このパターンがユーティリティクラスとして提供されています。
| フレームワーク | クラス名 |
|---|---|
| Bootstrap 5 | .visually-hidden |
| Tailwind CSS | .sr-only |
自前でCSSを書かなくても利用できるため、フレームワークを利用している場合はこれらのクラスを活用すると便利です。
CSSの小さな工夫でアクセシブルなwebを
今回紹介した3つのテクニックをまとめると以下になります。
-
:focus-visible: キーボードユーザーにはフォーカスを見せつつ、マウスユーザーには余計なoutlineを見せない。 - カラーコントラスト: テキストと背景に十分なコントラスト比を確保して、色覚特性や視力に関わらず読みやすくする。
-
visually-hidden: 見た目は隠しつつ、スクリーンリーダーユーザーに必要な情報を伝える。
前回の記事で紹介したクリッカブルエリアの調整やprefers-reduced-motionと合わせて、CSSでのアクセシビリティ対応を意識していきましょう。
小さな改修でもユーザーの体験が大きく変わることがあるので、少しずつ取り入れていくのがおすすめです。
最後までお読みいただき、ありがとうございました!!
Discussion