結果的に、使いやすさが大きく損なわれ、「使えるのに使えない」状態に陥ります。
具体例:業務での困りごと
Aさんは大量のデータをシステムに入力する業務を担当しており、作業をスピードアップするためキーボード操作で画面を移動しています。
ところが、フォーカスが見えない画面では、どのボタンが選択されているか分かりません。
その結果、登録ボタンを押すつもりがキャンセルを押してしまうなどのミスが頻発し、業務効率が下がりました。
以下のデモでTabキーを押してフォーカスの違いを体験してください。
悪い例: フォーカスが見えない
.button:focus {
outline: none;
}
.link:focus {
outline: none;
}
.button {
padding: 12px 24px;
background: #007bff;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
}
.link {
color: #007bff;
text-decoration: none;
padding: 8px;
}
良い例: フォーカスがしっかり見える
.button:focus-visible {
outline: 2px solid #005fcc;
outline-offset: 2px;
}
.link:focus-visible {
outline: 2px solid #005fcc;
outline-offset: 2px;
}
.button {
padding: 12px 24px;
background: #007bff;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
}
.link {
color: #007bff;
text-decoration: none;
padding: 8px;
border-radius: 4px;
}
- 機能要件に「フォーカス可能要素で、キーボード操作時に視認可能なフォーカススタイルを表示する」を明記する
- コンポーネントにフォーカス状態を定義する(FigmaではVariantsで管理する)
- 推奨スタイルか確認する
- より厳しくする場合は、背景や非フォーカス状態とのコントラスト比が3:1以上、太さが2px以上
:focus-visible 擬似クラスでフォーカスリングを当てる
- UIライブラリのフォーカス管理機能を活用する
最小限の実装例
:focus-visible {
outline: 2px solid #005fcc;
outline-offset: 2px;
}
- Tabキーで画面全体を巡回し、フォーカス表示を確認する
- コントラストが背景に埋もれていないか目視で確認する(3:1が目安。ツールを使う場合はフォーカスリング色と背景色でチェック)
- フォーカスが見えづらい箇所のフィードバックを収集する
- 気づいた時点で小まめに修正し継続改善する
要素と重ならない位置でフォーカススタイルを表示できます。
.button:focus-visible {
outline: 2px solid #ff6b35;
outline-offset: 4px;
}
.link:focus-visible {
outline: 2px solid #ff6b35;
outline-offset: 2px;
}
.button {
background-color: #007bff;
color: white;
border: none;
padding: 12px 24px;
margin: 8px;
border-radius: 4px;
cursor: pointer;
}
.link {
color: #007bff;
text-decoration: none;
padding: 8px;
border-radius: 4px;
margin: 8px;
display: inline-block;
}
box-shadowを使用するとより柔軟なデザインを実現できます。
.button:focus-visible {
outline: 2px solid transparent;
box-shadow:
0 0 0 3px rgba(59, 130, 246, 0.6),
0 0 8px 2px rgba(59, 130, 246, 0.3),
0 4px 12px rgba(59, 130, 246, 0.3),
inset 0 1px 0 rgba(255, 255, 255, 0.2);
}
.link:focus-visible {
outline: 2px solid transparent;
box-shadow:
0 0 0 2px rgba(30, 64, 175, 0.6),
0 0 4px 1px rgba(30, 64, 175, 0.3);
background-color: rgba(30, 64, 175, 0.08);
border-radius: 3px;
}
.button {
background: linear-gradient(135deg, #3b82f6, #1d4ed8);
color: white;
border: none;
padding: 14px 28px;
margin: 8px;
border-radius: 12px;
cursor: pointer;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
transition: all 0.2s ease;
}
.link {
color: #1e40af;
text-decoration: underline;
padding: 4px 2px;
margin: 8px;
display: inline;
transition: all 0.2s ease;
}
- HTML構造を見直す(最優先)
tabindexを使用する
tabindex="-1":JavaScriptからのみフォーカス可能
tabindex="0":カスタム要素などを通常のタブ順序に含める
tabindex="1" 以上:タブ順序を強制的に変更する(使わない)
- CSSで視覚的な順序だけを変更する
モーダル表示時にはフォーカスをモーダル内で循環させます。
多くのUIライブラリはこの機能を提供しているため、利用を検討してください。
自前で実装をする場合は以下のライブラリを検討してください。
Material-UIやChakra UIなどでは、テーマやコンポーネント単位でfocus-visibleスタイルの上書きが可能です。
まとめて適用することで、個別対応の手間を減らせます。
| 擬似クラス | 特徴 | 使用場面 |
|---|
:focus | マウスでもキーボードでもフォーカス時に有効。古いブラウザでも使える | 後方互換性が必要な場合 |
:focus-visible | 基本的には推奨。キーボード操作時など、「フォーカスを表示するべき場合のみ」に有効 | モダンブラウザでのフォーカス表示 |
:focus-within | 子要素にフォーカスがある場合も親要素に適用される | フォーム全体やカードコンポーネントのハイライト |
box-shadowを使用することで柔軟なデザインを実装できます。ただし、Windowsのハイコントラストモードでは表示されないため、outline: 2px solid transparentと併用します。ハイコントラストモードではtransparentが適切な色に変換されます。
outline: 2px solid transparent;
box-shadow: 0 0 0 3px red;
transition: outline-offset 0.25s ease-out;
/* アニメーションを望まないユーザーにはアニメーションを無効化する */
@media (prefers-reduced-motion: reduce) {
@media (prefers-color-scheme: dark) {
outline: 2px solid var(--focus-ring);
- 最初の要素と最後の要素のフォーカス要素を取得
- 最後の要素でTab → 最初の要素へ戻す
- 最初の要素でShift+Tab → 最後の要素へ戻す
- モーダル表示時に最初の要素へフォーカス