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.
- 前にフォーカスがしていた要素がフォーカスを示していたおり、スクリプトによって他の要素にフォーカスが移動して場合、新たなフォーカスした要素に視覚的なフォーカスを表示する。反対に以前フォーカスしていた要素がフォーカスを示さずに、スクリプトによって他の要素にフォーカスが移動した場合、新たな要素に視覚的なフォーカスを表示しない。
- 新しく表示された要素に自動的にフォーカスが当たった場合(例えば、開いたばかりのダイアログのアクションボタンなど)、その要素に視覚的なフォーカスを表示する
このように、focus()
メソッドにより :focus-visible
が適用されるかどうかは、前にフォーカスしていた要素により決定されるのです。
focus({ focusVisible: true })
オプション
focus()
メソッドにより :focus-visible
が適用されるかどうかその時の状況に依存しているため、時により不都合が生じます。このような問題に対処するために、focus
メソッドに指定可能なオプションとして focusVisible
が提案されています。
このオプションは boolean
値を取り、true
が指定された場合には常に新たにフォーカスされた要素に対して視覚的なフォーカスを表示します。true
が指定されない場合には元のとおり前にフォーカスしていた要素により決定されます。
次の例が現在 Firefox 104 以降でのみ動作します。「Focus B」をいかなる方法でクリックしたとしても、B のボタンにアウトラインが表示されます。