本文へスキップ

フォーカスリングの設計

:focus-visible で「キーボードのときだけ」2px のリングを 2px 離して描く。角丸に追従し、ダーク背景では白+藍の二重輪。マウスクリックでは出ない。

ENGLISH

Focus Ring (:focus-visible)

  • JS
約156行基本のUI部品 / アクセシブルUI の一覧 →

プレビュー

クリック

操作クリック/タップで動きます。

仕様書

向く場面
  • デザインシステムのフォーカス表示を決める
  • ボタン・リンク・入力欄・チェックの共通処方
  • 暗い背景の上でもリングを見せたい画面
避ける場面
  • outline:none だけを書く
  • :focus に描く(マウスでも出て消される)
  • 1 色のリングを暗い地に置く
構成要素
  • ボタン
  • リンク
  • 入力欄とチェック
  • 暗い背景の行
  • 判定結果の帯
持っている状態
  • 通常
  • フォーカス
キーボード

Tab/Shift+Tab で各要素へ移動すると 2px のリングが 2px 離れて出る。マウスクリックでは出ない(入力欄だけは出る)

支援技術

:focus-visible に outline 2px+outline-offset 2px、暗い地は白の内輪+藍の外輪。ブラウザ既定の outline を消さず同じ強さの代替を置く

動き

なし

デザインの要点

  • outline はブラウザ既定を消さない。消すなら同じ強さの代替を必ず置く。outline:none だけの CSS は事故の温床
  • :focus ではなく :focus-visible に描く。マウスで押した瞬間にリングが出ると「壊れた」ように見えて消される
  • outline-offset: 2px で要素から少し離すと、角丸の形に沿ったまま背景色を問わず見える
  • 暗い地の上では白い内輪+藍の外輪の二重にする。1色のリングは地の色と同化して消える

プロのサイトでの実例

実例は「型の使われ方」の観察であり、コード・ロゴの転載ではありません。サイト側の更新で見え方が変わることがあります。

使いどころ

デザインシステムでフォーカス表示を1か所に決めるときの処方。ボタン・リンク・入力欄・チェックに同じ規則を当てておくと、部品が増えてもフォーカスの見え方が揺れない。とくに、デザイナーから「クリックしたときに青い枠が出るのが気持ち悪い」と言われて outline:none を書きたくなった場面こそ、この処方へ置き換える価値がある。逆に、明るい地しか存在しない単純なサイトでは二重輪まで用意する必要はなく、1色のリングで足りる。ブラウザ既定の outline をそのまま使う社内ツールなら、消さない限り追加の実装は要らない。

仕組み

:focus ではなく :focus-visible に outline: 2px solid と outline-offset: 2px を当てるのが骨格。:focus-visible はブラウザが「フォーカスの可視化が必要」と判断したときだけ真になるため、マウスでボタンを押したときはリングが出ず、テキスト入力欄では(キャレットの行き先を示す必要があるので)マウスでも出る。outline は border と違ってレイアウトを押し広げず、border-radius にも自動で追従する。暗い背景の行では outline: 2px solid #fff を内輪に、box-shadow: 0 0 0 5px #2b50c7 を外輪に重ねて二重にしている。見本の JS は pointerdown と keydown を捕捉して直前の操作がマウスかキーボードかを帯に出し、実際に matches(":focus-visible") を読んで判定結果を並べて見せている。

実装の注意

最大の落とし穴は outline:none を書いて代替を置き忘れること。キーボード利用者にとっては「今どこにいるか」が完全に消える変更なのに、マウスで触る限り何も壊れて見えないためレビューをすり抜けやすい。次に多いのが :focus に描く実装で、マウスクリックでもリングが出るので「バグに見える」と言われ、結局 outline:none へ戻される。outline-offset を 0 のまま縁へ密着させると、要素の背景とリングの色が近いときに輪郭が溶ける。overflow:hidden の親の中ではリングが切られるので、その場合は box-shadow でリングを描くか親の overflow を見直す。box-shadow で描くときは、要素に別の影が付いていればカンマ区切りで両方書く必要がある。

アクセシビリティ

WCAG 2.4.7「フォーカスの可視化」と、2.2 で追加された 2.4.11「フォーカスの外観」が関係する。後者はフォーカス表示の面積と、隣接する色とのコントラスト比 3:1 以上を求める考え方で、2px 幅で要素を囲む輪はこの目安を満たしやすい。outline-offset を取ると、要素自身の色ではなく周囲の背景とのコントラストで評価できるようになるのも利点。Windows のハイコントラストモード(forced-colors)では色指定が上書きされるため、outline の色を system color に切り替えるか、少なくとも outline:none を書かないことで既定の表示を残す。:focus-visible が未対応の環境まで面倒を見るなら :focus のフォールバックと二段構えにする。

調整して使う

調整する値は太さ・間隔・色の3つ。太さ 2px は下限に近く、細くするほど小さな部品(チェックボックスやアイコンボタン)で見落としやすくなる。間隔(outline-offset)は 2px を基準に、密なツールバーでは隣の部品とリングが接触するので 1px へ詰め、余白の広いフォームでは 3px まで開いてよい。色はブランド色をそのまま使いたくなるが、ボタンの塗りと同系色だと輪が溶けるので、フォーカス専用に1色を確保して全部品で共有するのが安全。暗い地では見本のように白の内輪+濃色の外輪にすると、どんな背景でも片方は必ず見える。

コード(コピーして使えます)

<div class="fr-wrap">
  <div class="fr-row">
    <button type="button" class="fr-btn fr-primary">保存する</button>
    <button type="button" class="fr-btn fr-ghost">キャンセル</button>
    <a href="#fr-help" class="fr-link">ヘルプを見る</a>
  </div>
  <div class="fr-row">
    <label class="fr-field"><span>メール</span><input type="email" placeholder="you@example.com" autocomplete="off"></label>
    <label class="fr-check"><input type="checkbox"><span>通知を受け取る</span></label>
  </div>
  <div class="fr-row fr-dark">
    <button type="button" class="fr-btn fr-ondark">ダーク背景では二重の輪</button>
  </div>
  <div class="fr-row">
    <button type="button" class="fr-sim" id="fr-sim">Tab を押す(模擬)</button>
    <span class="fr-simnote">実際の Tab キーでも同じリングが出ます</span>
  </div>
  <div class="fr-band"><span class="fr-tag">最後の操作</span><span id="fr-msg">枠内をクリックしてから Tab(キーボード)とクリック(マウス)を試す</span></div>
</div>

タグ

同じカテゴリ「アクセシブルUI」のほかのパーツ

関連パーツ