任意の要素に対してブラウザデフォルトのフォーカスリングを適用する方法

任意の要素に対して、ブラウザデフォルトのフォーカスリングが描画されるように明示的に設定したいことがある。たとえば、スタイリングの都合により一度取り除いたフォーカスリングを、ふたたび適用したいとき。

フォーカスリングのスタイルは、ブラウザの種別や状況によってまちまちであるため、CSSでそれらしいものをエミュレートするのが難しい。そのため、同じものを呼び出せるような特別なやり方を採用できると望ましい。

一つの方法として、outline: revertを適用すればデフォルトの挙動を復元できる。

* {
  outline: 0;
}

button {
  outline: revert;
}

しかし場合によっては、通常はフォーカスリングが描画されない要素に対して、ブラウザのデフォルトと同じフォーカスリングが描画されるようにしたい、ということもあるだろう。この場合、outline: revertではフォーカスリングを適用できない。

代わりに、次のように指定することでフォーカスリングを描画させられる。

.card:focus-within {
  outline: auto;
  outline: auto -webkit-focus-ring-color; /* for Chrome */
}

デフォルトのフォーカスリングを適用するための方法はブラウザによって異なるため、この方法では、それぞれに対応するためにoutlineプロパティを二重に宣言する。

まずFirefox/Safariでは、次の条件に一致するときにデフォルトのフォーカスリングが描画される。

outline-styleの値がautoの場合、outline-colorの値は無視される。

Firefoxにおいては、accent-colorが指定されている場合、その値がフォーカスリングの色として適用される。

一方Chromeでは、次の条件に一致するときにデフォルトのフォーカスリングが描画される。

-webkit-focus-ring-colorはブラウザの独自実装であり、標準化されていない。outline-colorの値を指定しなければ、currentcolorがフォーカスリングの色として適用されることになる。

.card:focus-within {
  outline: auto; /* `outline-color`は暗黙的にgreenになる */
  color: green;
}

これらの二重の宣言はブラウザで次のように動作する。

outline: autooutline: auto -webkit-focus-ring-color
Chrome❌(currentcolorで描画される)✅(カスケードによって優先される)
Firefox❌(パースエラーとなり無視される)
Safari✅(カスケードによって打ち消される)✅(カスケードによって優先される)

デフォルトのスタイルを適用するためには、Chromeではoutline: auto -webkit-focus-ring-colorを使用する必要がある。このやり方の場合、カスケードによって前者のoutline: autoは打ち消されて、後者の宣言が優先される。

Firefoxではoutline: autoを使用する必要がある。後者のoutline: auto -webkit-focus-ring-colorはパースエラーとなり無視されて、前者の宣言が適用される。

Safariではそのどちらの宣言を使用してもデフォルトのスタイルが適用される。標準仕様を採用するという意味では、前者のoutline: autoを使用するのが好ましいが、このやり方では、カスケードによって後者のoutline: auto -webkit-focus-ring-colorが優先されることになる。

参考文献