autofocusがグローバル属性になったのでなんか書く
HTML, React2019 年 8 月末、HTML LS で、autofocus 属性がグローバル属性となった。
ブラウザの対応が進めば、全ての要素で autofocus を使用できる。
autofocus属性とは
autofocus 属性は、ページの読み込み時に自動的にフォーカスする要素を指定するもの。
これまで autofocus
は、button, input など、フォーカス可能な要素でしか使用できなかった。
一方で、全ての要素は、tabindex
または contenteditable
属性を追加することでフォーカスが可能である。
したがって、autofocus
は全ての HTML 要素で使用できるべき、という内容の Issue が 4 月に上がってた。
Move autofocus content attribute to HTMLElement · Issue #4563 · whatwg/html
そして、それに関する PR が今年の8月末に merge され、autofocus
はグローバルとなった。
Make 'autofocus' a global attribute by tkent-google · Pull Request #4830 · whatwg/html
現在、autofocus 属性は HTMLOrSVGElement
に含まれている。(SVGで autofocus、とは…)
HTML LSの例では、 contenteditable
属性のある div
要素に autofocus を適用している。
HTML LS The autofocus attribute
試す
下記のHTMLは、div
要素と input
要素の両方に autofocus
属性が追加されている。
そして、div
要素はフォーカス可能。
html
<div autofocus contenteditable>hoge</div>
<input autofocus type="text" />
これまでは、div
要素の autofocus
は無視され、input
要素にフォーカスされた。
しかし、これからは div
要素の方にフォーカスされる。
要素生成時のautofocus
ここからは小ネタ。
autofocus
属性のついた要素は、基本的にページを読み込んだ時にフォーカスされる。
ただし、動的に生成される場合、ブラウザの挙動はそれぞれ異なる。
例えば Chrome では、「ページ読みこみ後にユーザーが他の要素にフォーカスしていない」「他に autofocus
を持つ要素が生成されていない」状態で autofocus
属性のついた要素が動的に生成される場合、自動的にフォーカスする挙動をとる。
Firefox は、動的に生成された autofocus
付きの要素にはフォーカスをしない。
Safari は独特で、ページロード時と生成時の両方でフォーカスする。
autofocus
ではないけど、dialog
要素のフォーカス挙動もそれぞれ異なる。
例えば showModal()
した時、Chrome では autofocus
の有無に関わらず、dialog
内の input
にフォーカスする。
つまり、内部的に autofocus
のように振る舞う。(この辺の実装は 1 バイトも読んでなくて憶測)
それにつられて Firefox で試しても、autofocus
の有無に関わらず、showModal()
を通して input
にフォーカスすることはない。
このように、autofocus のタイミングは何もかも違うので、ブラウザ間の差異を埋めるのは難しい。
ReactのautoFocus
一方、React に autofocus
属性は存在しない。
代わりに、従来からフォーカス可能だった要素が autoFocus
prop を持つ Element として列挙され、autoFocus={true}
が渡っていれば、mount 時に focus()
を実行する。
要するに、先に述べたようなブラウザ差異に対しての Polyfill としても機能する。
autoFocus
の要素に、autofocus
属性は付かない。
ただし、Hydrate する時は別で、autoFocus
な要素にはしっかり autofocus
属性が付く。
これは hydrateInstance の挙動の問題と、 Server そして Client 両方で DOM の構造を保つための解決案だそう。
autoFocus doesn't work with SSR in React 16 · Issue #11159 · facebook/react
autofocusは良いのか
多くの場合は使わなくて済む。
- ブラウザによって挙動がばらばら
- 直接飛ぶので、スクリーンリーダーに適切なラベルを与えられない可能性がある
- モバイルなどでフォーカスした時、キーボードが出て煩わしいことがある
- ページ読み込み直後に、ショートカットキーでの操作を阻害する恐れがある
- 本当にフォーカス制御してほしい対話型なケースでうまく機能しない
良いことがない。
強いて言えば data:text/html, <html contenteditable autofocus>
でブラウザをメモ帳化した時、フォーカスがいらなくなることぐらい。
autofocus の使用に関するガイドラインはないけど、WCAG の達成基準で言えば、「予測可能」の 3.2.2が近い。
ユーザーの意識なくコンテキストを変更すると、ユーザーが混乱する、と言うもの。
ユーザーからのアクションに応じて、コンテンツを切り替える分には問題ない。
となると(基本的に)ページの読み込み時にしか行われない autofocus の使用が、問題を孕んでいるように思える。
ユースケースとして多いのが、入力フォームへのジャンプか。
ユーザーがこれからフォームに移ることを予測できて、かつ入力事項や注意事項を完全に理解し、ショートカットキーを使わず、いつでも PC を持ち歩いているような人でないと不便なので、いらない。
React の autoFocus
は、mount 時の focus()
をサポートするので、対話的なコンテンツなどで使いどころがありそう。
ただ、eslint-plugin-jsx-a11y には、autoFocus の使用を禁止する rule がある。
no-autofocus.md at master · evcohen/eslint-plugin-jsx-a11y
終わり
オチなし。