TPAC 2019現地レポート2
チーフアクセシビリティ・エンジニア 黒澤前回に引き続きTPAC 2019の現地レポートをお届けします。
TPACではW3Cの様々なWorking Groupなどが1カ所に集まることもあって、複数のグループによる合同ミーティングも数多く行われています。この記事では2日目、9月17日に行われたARIA Working GroupとWeb Componentsの合同ミーティングなどから興味深かったものを紹介します。
カスタム要素のフォーカスの挙動
通常のHTML要素はフォーカスを受け取るかどうかがOSの一般的挙動を反映したものになっています(OSの一般的な設定を反映できるようにブラウザーがOSごとに調整しています)。たとえば、macOSのネイティブアプリケーションではテキスト入力欄はフォーカスを受け取りますが、ボタンはフォーカスを受け取りません。SafariやFirefoxなどのブラウザーはmacOSの挙動と一致するようにHTMLの要素に対して調整を行っています。通常設定では<input type="text">
はフォーカスを受け取りますが、<input type="button">
はフォーカスを受け取りません。OSの設定を変更するか(Firefox)、ブラウザーの設定を変更する(Safari)ことでボタンなどもフォーカスを受け取れるようになります。
このような挙動を再現することは現在のカスタム要素の仕様では実現できません(既存のWeb技術では再現できません)。tabindex属性を指定するとOSやブラウザーの設定とは一貫性のない挙動になります。
そこで、GoogleのRakina Zata AmniさんからElementInternalsに専用のプロパティを追加する提案がありました(Default focus behaviors for custom elements)。
class MyButton extends HTMLElement {
constructor() {
super();
this._internals = this.attachInternals();
this._internals.matchFocusBehaviorOf = "input[type='button']";
}
}
上記のように記述することで、<my-button>
のフォーカスに関する挙動をmatchFocusBehaviorOf
で指定した要素(<input type="button">
)と同じにするというものです。
この提案は方向性については受け入れましたが、具体的な方法については議論がありました。提案ではmatchFocusBehaviorOf
の指定方法はCSSセレクターで表現することになっていますが、それよりはフォーカスの挙動をカテゴリ化し、カテゴリを指定できるようにしたほうが良いだろうということになりました。
この提案は興味深いのですが、ある要素がキーボードで操作できるのかを外から判断することが(より)難しくなるため、キーボードトラップを実装する際などに、フォーカス可能かどうかを簡単に判断できる方法が別途必要になるだろうと考えています。
Shadow Treeを超えて要素を参照する方法
WAI-ARIAにはaria-activedescendant属性など、参照したい要素をid属性値で指定する属性が複数あります。
<div role="combobox">
<input aria-activedescendant="opt1">
<ul role="listbox">
<li role="option" id="opt1">Option 1</li>
<li role="option" id="opt2">Option 2</li>
<li role="option" id="opt3">Option 3</li>
</ul>
</div>
しかし、この参照方法はShadow DOMでは機能しません。Shadow DOMではid属性値はShadow Treeの中で閉じていて、外側のid属性値は参照できないためです。
<custom-combobox>
#shadow-root (open)
| <!-- aria-activedescendantはOption 1を参照できていない -->
| <input aria-activedescendant="opt1">
| <slot></slot>
<custom-optionlist>
<x-option id="opt1">Option 1</x-option>
<x-option id="opt2">Option 2</x-option>
<x-option id="opt3">Option 3</x-option>
</custom-optionlist>
</custom-combobox>
そこでGoogleのAlice BoxhallさんはからShadow Treeの中から外の要素を参照できるAPIの提案がありました。
前述のようなShadow Treeを含んだDOMがある場合、Shadow Treeをまたいで
const input = comboBox.shadowRoot.querySelector("input");
const optionList = comboBox.querySelector("custom-optionlist");
input.activeDescendantElement = optionList.firstChild;
上記のように要素を参照できるようにする、というものです。
この提案はShadow DOMのカプセル化モデルに直結するため、実装側(ブラウザーベンダー)は実装を考えればどうしても難しいと回答せざるをえないし、提案側はユースケースを考えれば何らかの方法を標準化せざるをえない、というジレンマに陥っているように感じます。この議論がなされたのは今回が初めてではありませんが、今回も解決策は見つけられず、議論継続となりました。
現時点では制作側でShadow DOMをまたがるような参照を避けるしかないと考えています。