rock

focus() メソッドで CSS の :focus-visible 擬似クラスが適用されるかどうかは最後の操作によって異なる

:focus-visible 擬似クラスはユーザーの入力方法によって異なるフォーカス表示をしたい時に便利です。この擬似クラスはキーボード操作によりフォーカスされた場合に適用されますが、マウス操作によりフォーカスした場合には適用されません。 それでは、JavaScript の focus()メソッドによりフォーカスされた場合には、`:focus-visible` 擬似クラスは適用されるのでしょうか?実はこれは最後 `focus()` メソッドが呼ばれる前に要素にフォーカスがあったかどうかにより異なります。

:focus-visible 擬似クラスはユーザーの入力方法によって異なるフォーカス表示をしたいときに便利です。この擬似クラスはキーボード操作によりフォーカスされた場合に適用されますが、マウス操作によりフォーカスした場合には適用されません。

それでは、JavaScript の focus() メソッドによりフォーカスされた場合には、:focus-visible 擬似クラスは適用されるのでしょうか?実はこれは最後 focus() メソッドが呼ばれる前に要素にフォーカスがあったかどうかにより異なります。

focus() メソッドによるフォーカスリングの表示

実際に focus() メソッドによる :focus-visible 擬似クラスの違いを確かめてみましょう。下記の CodePen では「A」のボタンは :focus 擬似クラスで青いアウトラインを「B」のボタンでは :focus-visible で赤いアウトラインを表示するようにスタイリングしています。

A のボタンはマウスによる操作とキーボードによる操作どちらでもアウトラインが表示されますが、B のボタンは Tab キーによるキーボード操作でのみアウトラインが表示されることがわかります。

「Focus A」ボタンをクリックすると A のボタンに「Focus B」ボタンをクリックすると B のボタンにそれぞれ JavaScript によりフォーカスされます。「Focus A」にクリックすると focus() メソッドが呼ばれたことによりいかなる場合でも A のボタンにアウトラインが表示されます。

:focus-visible 擬似クラスを使用している B のボタンの場合にはどうでしょう。マウス操作により「Focus B」ボタンをクリックしたときには B のボタンにアウトラインが表示されないのに対して、キーボード操作で「Focus B」ボタンをクリックしたときには B のボタンにアウトラインが表示されることがわかります。

:focus-visible の仕様を確認する

どうしてこのような挙動となるのか、:focus-visible の仕様書を確認してみましょう。以下のように記述されています。

  • If the previously-focused element indicated focus, and a script causes focus to move elsewhere, indicate focus on the newly focused element.

Conversely, if the previously-focused element did not indicate focus, and a script causes focus to move elsewhere, don’t indicate focus on the newly focused element.

  • If a newly-displayed element automatically gains focus (such as an action button in a freshly opened dialog), that element should indicate focus.

Selectors Level 4

  • 前にフォーカスがしていた要素がフォーカスを示していたおり、スクリプトによって他の要素にフォーカスが移動して場合、新たなフォーカスした要素に視覚的なフォーカスを表示する。反対に以前フォーカスしていた要素がフォーカスを示さずに、スクリプトによって他の要素にフォーカスが移動した場合、新たな要素に視覚的なフォーカスを表示しない。
  • 新しく表示された要素に自動的にフォーカスが当たった場合(例えば、開いたばかりのダイアログのアクションボタンなど)、その要素に視覚的なフォーカスを表示する

このように、focus() メソッドにより :focus-visible が適用されるかどうかは、前にフォーカスしていた要素により決定されるのです。

focus({ focusVisible: true }) オプション

focus() メソッドにより :focus-visible が適用されるかどうかその時の状況に依存しているため、時により不都合が生じます。このような問題に対処するために、focus メソッドに指定可能なオプションとして focusVisible が提案されています。

このオプションは boolean 値を取り、true が指定された場合には常に新たにフォーカスされた要素に対して視覚的なフォーカスを表示します。true が指定されない場合には元のとおり前にフォーカスしていた要素により決定されます。

次の例が現在 Firefox 104 以降でのみ動作します。「Focus B」をいかなる方法でクリックしたとしても、B のボタンにアウトラインが表示されます。


Contributors

> GitHub で修正を提案する
この記事をシェアする
はてなブックマークに追加

関連記事