👏

スクリーンリーダー観点からのHTMLタグの使い方

に公開

今回スクリーンリーダーでHTMLタグがどのように挙動するかと、具体的なHTMLタグの使い方をまとめました。

背景

HTMLタグの使い方は難しいです。
というのもHTML Living StandardやMDNを参照しても解釈の仕方が様々で、結局明確な使い方がわからない場合があります。

一方、アクセシビリティ観点からのHTMLタグの挙動を見ると明確なメリットや使い方が存在し、使い所がわかりやすくなって驚きました。

アクセシビリティ対応は大変ですが、よりコード品質の高いものを提供するためにぜひ学んだ方が良いと思い記事にしています。

前提

スクリーンリーダーはMacOSのVoiceOverで検証しています。
また、HTMLタグと大きくまとめていますが、今回はランドマークロールというrole属性の話となります。(見出しなども今後まとめる予定です)

HTMLタグのランドマークロールとは

HTMLタグにはrole属性というものがあり、これはHTMLタグの役割を表します。
例えば、buttonタグにはrole="button"という属性がデフォルトで存在します。

この中でランドマークロールと呼ばれるグループにはスクリーンリーダーで以下の機能を有することができます。

  1. ランドマークが有している情報(ラベルとランドマーク情報)を読み上げる
  2. ランドマークの場所にキーボード操作で簡単にアクセスすることができます

つまり、ランドマークロールがあることによって、特定の領域を名称から簡単に探し出すことができ、その領域にアクセスできるようになります。

このように、ランドマークロールを持つHTMLタグというのは、スクリーンリーダーのユーザービリティにおいて非常に重要なタグとなります。

どのようなHTMLタグが当てはまるか一覧を表にまとめましたしたので、以下のHTMLタグを使うときには気をつけてみてください。

HTML タグ ランドマーク種別 VoiceOver での日本語読み上げ例
<header> banner バナー
<footer> contentinfo コンテンツ情報
<main> main メイン
<nav> navigation ナビゲーション
<aside> complementary 補足
<form> form フォーム
<search> search 検索
<section> region 領域
<article> article 記事

スクリーンリーダーの動作説明

テキスト上ではわかりにくい部分もあると思うので、具体的な動作を説明します。
理解を深めるために、ぜひお手元でMacOSのスクリーンリーダーであるVoiceOverを起動してみてください。
https://support.apple.com/ja-jp/guide/voiceover/cpvokys07/mac

VoiceOverからランドマークロールのナビゲーション機能を使います

  1. VoiceOverを起動します。
  2. VOキー + U でローターを表示し、左右の矢印キーで「ランドマーク」を表示させます。
  3. ページ内のランドマークの箇所が一覧で表示されます。

このときに、タグが持つデフォルトの読み上げテキストとaria-labelやaria-labelledbyで付与される任意のテキストの両方が表示されます。
aria-labelなどがない場合、タグの持つデフォルトの読み上げのみが表示されます。

ランドマークロールをもつHTMLタグの使い方

いままでアクセシビリティに触れてこなかった人たちもスクリーンリーダーの動作の理解が少し深まったと思います。
次にランドマークロールをもつHTMLタグで気をつけるべき内容を説明します。

ページ内を適切にナビゲーションができるように設置する

ページ内のどこのコンテンツでも簡単にアクセスできるようにランドマークロールを配置します。
具体的には、ページ内コンテンツは必ずランドマークに内包されるようにします。
また、ランドマークロール内のコンテンツが多すぎる場合、内部をランドマークで分割することも検討します。

乱用をしない

ランドマークを適切に設置することは重要ですが、逆に多すぎるとローター上に多くのナビゲーション先がリストされてしまい、ユーザーが目的のコンテンツにアクセスしづらくなります。

重複しない

ランドマークは重複しないように設置をします。

例えば、下層のページのインデックスとなるような扉ページの場合、メインコンテンツ自体が下層ナビゲーションとなります。
その場合、mainタグもしくはnavタグどちらかのみを使用するようにしましょう。

重複のNG例

<body>
  <header></header>
  <main aria-label="メインコンテンツ">
      <nav aria-label="下層ページ一覧">
        <ul>
          <li><a href="/about">会社概要</a></li>
          <li><a href="/service">サービス紹介</a></li>
          <li><a href="/contact">お問い合わせ</a></li>
        </ul>
      </nav>
  </main>
  <footer></footer>
</body>

aria-label や aria-labelledby を使用して、ランドマークの役割を明確にする。

aria-label や aria-labelledby を利用することで、ローター上の読み上げ時のテキストも追加することができます。
これにより、より具体的にランドマークの中身を説明することが可能です。
特に1ページ内で複数使われるnavタグやsectionタグでは、目的のコンテンツにアクセスしやすくなるため、適切なラベル付けが重要です。

ランドマークを表すテキストが存在するならばaria-labelledby を優先する

ランドマーク内にそのランドマークを表すテキストが存在することが多いです。
aria-labelledby を使用することで、テキストの変更とともにランドマークの読み上げテキストも変更されるため、メンテナンス性が向上します。
まず、aria-labelledbyが使用できないか確認し、できない場合はaria-labelで対応しましょう。

例えば、sectionタグの中の見出しはそのセクションを表します。

<section aria-labelledby="profile-heading">
  <h2 id="profile-heading">プロフィール</h2>
  <p>このセクションでは著者のプロフィールを紹介します。</p>
</section>

読み上げを重複させない

また、読み上げ時にランドマークロールのデフォルトの読み上げとaria-*の読み上げが重複しないようにします。

<!-- NG例 -->
<article aria-label="記事">

各HTMLタグの使い方

各ランドマークロールを持つタグには使い方に注意事項があります。
今回HTMLの一般的な定義は省き、アクセシビリティ観点での使い方を説明します。

注意事項
一般的なサイトヘッダーやフッターを表し、サイトの中で 1 つだけ使われることが推奨されます。
aside、article、main、nav、sectionタグの子孫要素で使われる場合、ランドマークとして認識されません。

参考
https://developer.mozilla.org/ja/docs/Web/Accessibility/ARIA/Reference/Roles/banner_role
https://developer.mozilla.org/ja/docs/Web/Accessibility/ARIA/Reference/Roles/contentinfo_role

main タグ

注意事項
一般的なサイトのメインコンテンツ部分を表し、サイトの中で 1 つだけ使うことが推奨されます。

補足
mainタグがあることでローターからヘッダーの読み上げをスキップし、メインコンテンツにアクセスすることができます。ページの遷移ごとのヘッダーの読み上げを避けることができる、ユーザビリティにおいて重要なタグと言えます。

また、キーボード操作でも同様の機能を持たせるために、id とスキップリンクを付与しメインコンテンツに簡単にアクセスすることが推奨されます。
https://qiita.com/k8o/items/d45a5d33b2f1873ae88c

<body>
  <a href="#main-content" class="skip-link">メインコンテンツへスキップする</a>
  <header>
    <!-- ヘッダーのコンテンツ -->
  </header>
  <main id="main-content">
    <!-- メインページのコンテンツ -->
  </main>
</body>

参考
https://developer.mozilla.org/ja/docs/Web/Accessibility/ARIA/Reference/Roles/main_role

nav, aside, article タグ

注意事項
ページ内で複数使うことが可能です、その場合は、aria-labelやaria-labelledbyを使用して、ランドマークの役割を明確にしましょう。

参考
https://developer.mozilla.org/ja/docs/Web/Accessibility/ARIA/Reference/Roles/navigation_role
https://developer.mozilla.org/ja/docs/Web/Accessibility/ARIA/Reference/Roles/navigation_role
https://developer.mozilla.org/ja/docs/Web/Accessibility/ARIA/Reference/Roles/article_role

section タグ

注意事項
sectionタグは他のランドマークの役割が当てはまらないときに使われる汎用ランドマークです。
sectionタグがランドマークロールとして認識されるためには、aria-labelやaria-labelledbyを付与する必要があります。

<!-- aria-labelを使う例 -->
<section aria-label="お知らせ">
  <p>新しい機能が追加されました。</p>
</section>

<!-- aria-labelledbyを使う例(見出しがある場合) -->
<section aria-labelledby="news-heading">
  <h2 id="news-heading">ニュース</h2>
  <p>最新情報をお届けします。</p>
</section>

また、sectionタグは内部にhタグを持つことが推奨されますが、必須ではありません。
適切なナビゲーションを目的にする場合、見出しがなくてもsectionタグを使用しましょう。


引用: MDN

参考
https://developer.mozilla.org/ja/docs/Web/Accessibility/ARIA/Reference/Roles/region_role

form タグ

注意事項
form 単体ではランドマークロールとして機能せず、aria-label、aria-labelledbyを付与することでランドマークロールとして認識されます。

参考
https://developer.mozilla.org/ja/docs/Web/Accessibility/ARIA/Reference/Roles/form_role

search タグ

注意事項
formタグが不要でJavaScriptで検索機能を提供する場合、searchタグを使います。
formタグが検索機能を提供する場合、searchタグでのラップ、もしくはsearchロールを付与しましょう。

<!-- formタグが無い場合 -->
<search>
  <label>
    検索して絞り込み
    <input type="search" id="query" />
  </label>
  <label>
    <input type="checkbox" id="exact-only" />
    完全一致のみ
  </label>
</search>

<!-- formタグがありsearchタグでラップ -->
<search>
<form action="./search/">
  <label for="movie">動画を検索</label>
  <input type="search" id="movie" name="q" />
  <button type="submit">検索</button>
</form>
</search>

<!-- formタグがありロールを付与 -->
<form id="search" role="search">
  <label for="search-input">このサイトを検索</label>
  <input type="search" id="search-input" name="search" spellcheck="false" />
  <input value="検索" type="submit" />
</form>

参考
https://developer.mozilla.org/ja/docs/Web/Accessibility/ARIA/Reference/Roles/search_role

まとめ

スクリーンリーダー観点でのランドマークロールを持つHTMLタグの使い方をまとめました。
僕自身VoiceOverを触って初めてHTMLタグについての理解を深めていくことができ、コード品質を高めていくにはもっと触らないとなと痛感しています。

まだまだ理解しきれていないところもありますので、間違っている点やよりこうした方がよいという点がございましたらコメントいただければ幸いです。

Discussion