yuheijotaki.com

CSS :focus-visible とポリフィルの挙動を確認する

目次

概要

CSSの :focus-visible とそのポリフィルについて挙動を確認してみる。

:focus-visibleとは

MDN より

:focus-visible 疑似クラスは、ユーザーがキーボードなどの非ポインティングデバイスでページを操作している場合など、ブラウザーがフォーカスインジケーターを表示するべきと判断したときに、要素にマッチします。

従来の :focus だとクリックやタブ移動などどんなフォーカスでもスタイルが当たってしまうが、:focus-visible は「本当に必要なときだけ」アウトラインを表示できる。

ポリフィルについて

focus-visible ポリフィル:focus-visible に対応していないブラウザや、ブラウザごとに挙動が違う場合でもだいたい同じような動きをしてくれるスクリプト。

  • キーボード操作かマウス操作かを判定し、必要なときだけ .focus-visible クラスを付ける
  • JavaScriptで element.focus() などを呼び出した(=スクリプトでフォーカスを移動した)場合も考慮されている

スクリプトでフォーカスを移動した場合

ポリフィルはユーザーの操作(キーボード/マウス)だけでなく、JavaScriptから明示的にフォーカスを移動した場合も「アウトラインを出すべきかどうか」を判定している。

例えば下記のような コード がポリフィルの一部に含まれている:

function onFocus(event) {
  if (!isValidFocusTarget(event.target)) {
    return;
  }
  // 直前の操作がキーボードだった場合や、入力欄など「キーボードで使う要素」の場合だけ .focus-visible を付ける
  if (hadKeyboardEvent || focusTriggersKeyboardModality(event.target)) {
    event.target.classList.add('focus-visible');
  }
}

つまり、

  • 直前にキーボード操作があった場合
  • たとえばテキスト入力欄のように「キーボードで使う要素」の場合

のみアウトライン(.focus-visible)が付くようになっている。

逆にマウスやタッチ操作の直後に focus() された場合は .focus-visible を付けないため、意図しないアウトラインが出るのを防げる。

ブラウザごとの挙動差

ピンポイントな例だが、Safari では <dialog> 要素を showModal() で開いたとき、自動的にダイアログ内の最初のフォーカス可能要素にフォーカスが当たり、マウス操作でもアウトラインが表示されてしまう場合がある。
関連: 247416 – focus-visible is triggered when opening dialog using mouse

ポリフィルを使うとマウス操作でダイアログを開いた場合はアウトラインが表示されず、キーボード操作時だけ表示される。
ポリフィルを使うとこういった細かい違いも吸収できる。

まとめ

  • :focus-visible は「本当に必要なときだけ」フォーカスインジケーターを表示できる便利なCSS
  • ただしブラウザによっては挙動に差があり、特にダイアログの自動フォーカス時などに違和感が出ることがある
  • ポリフィルを使うとどのブラウザでもだいたい同じような挙動にはなりそう

ほか参考