https://zenn.dev/takepepe/articles/improve-a11y-and-testing

これまで、フロントエンドの a11y 改善・テスト拡充にあたり「どのように改善すべきか?どのように書くべきか?」という点がハードルだと感じていました。a11y tree を確認するには、dev tools の隅の隅をつつく必要があり、あまり体験の良いものではなく、気に入ったエクステンションもありませんでした。

Testing Library は「誰もがアクセスできるクエリー」を優先的につかうことを推奨していますが、アプリケーションがはじめから a11y に考慮された作りになっているとは限りません。これらの背景から「data-testid」のような、テスト向け属性に頼るワークアラウンドで乗り切ることも少なくありませんでした。

Full page accessibility tree

今年 1 月にリリースされたChrome98 の新機能として「Full page accessibility tree」を dev tools で確認できるようになりました。先日の Google I/O でもセッションがありましたので、詳細は動画をご確認ください。

この拡張により、DOM tree と a11y tree のビューをスイッチできます。「role:"名前"」 による木構造ビューを提供してくれるので、ランドマークや特定 Node が、どの様なアクセシブルネームで識別されているのか即座にわかります。もし、div ばかりで構築したアプリケーションであれば、この a11y tree と DOM がひどく乖離していることでしょう。この a11y tree が意図したものでないなら、改善のときです。

問題のコンポーネントを確認する

a11y 改善の対象として、問題のコンポーネントをみていきましょう。このコンポーネントは一般的な<Card />コンポーネントを一覧表示した<CardList />コンポーネントです

Storybook をコミットしていれば「どこが悪いのか?」を、より鮮明に把握することができます。特定の Story ページに遷移し「canvas tab」を押下、別タブでコンポーネントを確認します(キャプチャ右が別タブで開いた状態)

a11y tree はこの様になっていました。カードリストが、うまくセクショニングできていないことが分かります。

これは、<Card />コンポーネントが<div>でマークアップされたことが原因です。div は意味を持たないグループとして扱われるため、そのままでは a11y tree には現れません。

export const Card = ({ id, title, text }: Props) => (
  <div className={styles.module}>
    <h3>{title}</h3>
    <p>{text}</p>
    <a href={`/articles/${id}`}>詳細をみる</a>
  </div>
);

section に修正する

<div>タグを<section>タグに変更することで、Card コンポーネントはセクションとして識別されます。改善されたように見えますが、まだ role と、アクセシブルネームは持っていないため、支援技術によりよいマークアップにはなっていません。

export const Card = ({ id, title, text }: Props) => (
  <section className={styles.module}>
    <h3>{title}</h3>
    <p>{text}</p>
    <a href={`/articles/${id}`}>詳細をみる</a>
  </section>
);