アクセシビリティツリーを調べてみた


こんにちは、上條(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 パネルからアクセシビリティツリーが見れるようになりました。

Chromeのdevツールからアクセシビリティツリーを確認している画面のキャプチャ

アクセシビリティツリーの中身はアクセシビリティオブジェクトと呼ばれるオブジェクト構造になっています。

アクセシビリティオブジェクト

アクセシビリティオブジェクトの中身は4つに分類されます。

Name

要素のアクセシブルな名前です。タグ内のテキストや aria-label で指定されたテキストが対象となります。

<a href="">リンク</a>
<p aria-label="テキスト">テキスト</p>
aタグのNameは「リンク」となる
aria-labelを使用した場合、pタグのNameは「テキスト」となる

Description

要素のアクセシブルな説明です。想定される使用方法として、フォームの各項目の説明などが挙げられます。以下のサンプルはパスワードの inptut に対する説明のテキストを aria-describedby で紐づけたものです。「7文字以上で入力してください」というテキストは視覚的にはパスワードの input に対する説明だと理解できますが、アクセシビリティツリー上では input と関係のないものとして解釈されているため、明示的な指定が必要です。

パスワードのinputに対して「7文字以上で入力してください」という説明文がある画像
<form>
  <label for="password">
    パスワード
    <input type="password" id="password" aria-describedby="password-label" />
  </label>
  <p id="password-label">7文字以上で入力してください</p>
</form>
aria-describedby を使用しない場合、パスワード入力欄の Description は存在しない
aria-describedby を使用した場合、パスワード入力欄の Description は「7文字以上で入力してください」となる

Role

要素の役割を表します。p タグは paragraph、a タグは link という風に HTML の要素はデフォルトで role を持っています。そのため、適切に HTML を書いていれば明示的に指定することは基本的にありません。

aタグのデフォルトのRoleはlink
pタグのデフォルトのRoleはparagraph

例外として、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

ARIA Authoring Practices Guideで紹介されているTab UIの画像
tablist を使った場合、div の Role は tablist となる
tabpanel を使った場合、div の Role は tabpanel となる

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>
  )
}
チェックしていない状態の input の Checked は false となる
チェックした状態の input の Checked は true となる

WAI-ARIA のロール・ステート・プロパティとの違い

はじめ、上記4つが WAI-ARIA のロール・ステート・プロパティと似ているため少し混乱しました。WAI-ARIA のロール・ステート・プロパティは WAI-ARIA の属性を分類したもの、一方アクセシビリティオブジェクトの中身は HTML 要素が持つアクセシビリティ情報です。どちらも似ていますが別物なので、混同してしまわないよう注意が必要です。

まとめ

これまで何を指定するか、どのタグを使うかばかり重視していたので、指定したものがどのようにして支援技術に提供されるのかまで考えたことがありませんでした。アクセシビリティツリーが dev ツールで確認できるようになったことでどんな挙動になるのかが分かり、さらに理解が深まったように思います。

Gaji-Laboでは、 Next.js 経験が豊富なフロントエンドエンジニアを募集しています

弊社では Next.js の知見で事業作りに貢献したいフロントエンドエンジニアを募集しています。大きな制作会社や事業会社とはひと味もふた味も違う Gaji-Labo を味わいに来ませんか?

Next.js の設計・実装を得意とするフロントエンドエンジニア募集要項

もちろん、一緒にお仕事をしてくださるパートナーさんも随時募集中です。まずはお気軽に声をかけてください。お仕事お問い合わせや採用への応募、共に大歓迎です!

求人応募してみる!


投稿者 Kamijo Momoka

フロントエンドエンジニア。
HTML/CSS/JavaScript/WordPressでのサイト制作からNext.js/TypeScriptなどを使ったWebアプリ開発、FigmaでのUIデザインまで広く経験しています。 デザインエンジニアと名乗るのが夢です。