アクセシビリティツリーを調べてみた
こんにちは、上條(mk-0A0)です。
2023年12月12日に行われた #朝までマークアップ フォローアップsp にて、株式会社ディーゼロの ゆうてん さんが『もう迷わない!アクセシビリティのための HTML コーディング』というタイトルで発表されていました。HTML とアクセシビリティツリーの関係や、それを知ったうえでの WAI-ARIA の使い方などを解説されていて、アクセシビリティに入門したばかりの身としてとても勉強になりました。それ以降アクセシビリティツリーを意識するようになったので、自分の中での整理も兼ねて学んだことを記事にしたいと思います。
アクセシビリティツリーとは
サイト内のアクセシビリティに関する情報のツリー構造で、DOM や CSSOM を元に作られます。作成されたアクセシビリティツリーからアクセシビリティ API を通じて支援技術に情報が提供されます。
Accessibility tree (アクセシビリティツリー) – MDN Web Docs
アクセシビリティツリーは Chrome の dev ツールから確認できます。設定方法は以下の記事を参考にさせていただきました。
5. Full Accessibility Tree View – アクセシビリティの情報で要素を検証する | すべての開発者が知るべきGoogle Chromeの隠れた機能5選(Qiita)
設定すると dev ツールの Element パネルからアクセシビリティツリーが見れるようになりました。
アクセシビリティツリーの中身はアクセシビリティオブジェクトと呼ばれるオブジェクト構造になっています。
アクセシビリティオブジェクト
アクセシビリティオブジェクトの中身は4つに分類されます。
Name
要素のアクセシブルな名前です。タグ内のテキストや aria-label で指定されたテキストが対象となります。
<a href="">リンク</a>
<p aria-label="テキスト">テキスト</p>
Description
要素のアクセシブルな説明です。想定される使用方法として、フォームの各項目の説明などが挙げられます。以下のサンプルはパスワードの inptut に対する説明のテキストを aria-describedby で紐づけたものです。「7文字以上で入力してください」というテキストは視覚的にはパスワードの input に対する説明だと理解できますが、アクセシビリティツリー上では input と関係のないものとして解釈されているため、明示的な指定が必要です。
<form>
<label for="password">
パスワード
<input type="password" id="password" aria-describedby="password-label" />
</label>
<p id="password-label">7文字以上で入力してください</p>
</form>
Role
要素の役割を表します。p タグは paragraph、a タグは link という風に HTML の要素はデフォルトで role を持っています。そのため、適切に HTML を書いていれば明示的に指定することは基本的にありません。
例外として、Tab UI のように role は存在するけど HTML の要素がない UI というものがあります。WAI-ARIA を使ったサンプルが紹介されている ARIA Authoring Practices Guide (APG) の Tab UI を見ると、ボタンの親要素には tablist ロールを、タブのコンテンツ部分には tabpanel ロールを明示的に指定しています。これによって、ただの div ではなく tablist / tabpanel という適切なロールを持つことになります。
Example of Tabs with Automatic Activation | APG | WAI | W3C
State
要素の状態を表します。例えばチェックボックスの場合、視覚的にはチェックが付いているかどうかが分かりますが、アクセシビリティツリーからは何が変わったのかが分かりません。そのため aria-checked を使用してアクセシビリティツリー上からもチェックボックスの状態が分かるようにします。アクセシビリティツリーを確認すると Checked プロパティが変化しているのが分かります。(サンプルの作りやすさ優先で React を使用しています)
export default function Home() {
const [isChecked, setIsChecked] = useState(false)
return (
<form>
<label>
<input type="checkbox" checked={isChecked} aria-checked={isChecked} onChange={(e) => setIsChecked(e.target.checked)} />
個人情報の取扱に同意します
</label>
</form>
)
}
WAI-ARIA のロール・ステート・プロパティとの違い
はじめ、上記4つが WAI-ARIA のロール・ステート・プロパティと似ているため少し混乱しました。WAI-ARIA のロール・ステート・プロパティは WAI-ARIA の属性を分類したもの、一方アクセシビリティオブジェクトの中身は HTML 要素が持つアクセシビリティ情報です。どちらも似ていますが別物なので、混同してしまわないよう注意が必要です。
まとめ
これまで何を指定するか、どのタグを使うかばかり重視していたので、指定したものがどのようにして支援技術に提供されるのかまで考えたことがありませんでした。アクセシビリティツリーが dev ツールで確認できるようになったことでどんな挙動になるのかが分かり、さらに理解が深まったように思います。
Gaji-Laboでは、 Next.js 経験が豊富なフロントエンドエンジニアを募集しています
弊社では Next.js の知見で事業作りに貢献したいフロントエンドエンジニアを募集しています。大きな制作会社や事業会社とはひと味もふた味も違う Gaji-Labo を味わいに来ませんか?
Next.js の設計・実装を得意とするフロントエンドエンジニア募集要項
もちろん、一緒にお仕事をしてくださるパートナーさんも随時募集中です。まずはお気軽に声をかけてください。お仕事お問い合わせや採用への応募、共に大歓迎です!