先日、ふと「アクセシビリティを考慮したデータ・テーブルのコーディングってどうやるんだっけ?」と、思ったのでやり方をまとめてみます。これまでもセマンティックなコーディングはしていたものの、セマンティックス以外に注意すべき点はあるのか?データ・テーブルはスクリーンリーダーでどのように読まれるのか?が気になったので、調べて整理してみました。
主にWebAIMの「Creating Accessible Tables 」とWAI Web Accessibility Tutorialsの「Table Concepts 」という2つのサイトを参考にさせてもらいました。
ちなみに、データ・テーブルとはデータを表形式で表示する以下のようなテーブルのことを言います。
画像 | オリジナル | 91% | 85% | 81% |
---|---|---|---|---|
sample01.jpg | 582KB | 164KB | 128KB | 112KB |
sample02.jpg | 341KB | 89KB | 64KB | 55KB |
sample03.jpg | 398KB | 94KB | 72KB | 64KB |
sample04.jpg | 267KB | 54KB | 40KB | 34KB |
テーブルといってもシンプルなものから複雑なものまであるので、まずはシンプルなテーブルをコーディングする際に必要なことを「基本編」としてまとめます。複雑なテーブルについては後日整理します。
なにごとも、まずは基本から!
3つの基本
シンプルなテーブルのコーディングでは、以下の3つを確実に行います。この3つを守るだけでもデータ・テーブルをアクセシビリティを考慮したものにできます。
- テーブルの説明を入れる
- 表の見出しを指定する
- セルを適切な見出しに紐付ける
まずは基本を確実に、条件反射でできるくらいに習慣化できるといいですね。
1. テーブルの説明を入れる
見出しや説明なしにいきなりテーブルを見せられても(読まれても)わかりずらいので、テーブルの説明を入れます。テーブルの説明はcaption
要素に入れることが推奨されています。caption
要素で説明しきれない詳しい説明はsummary
属性を使って書きます(あとで`summary`についても説明します)。
caption要素の使い方
caption
要素は<table>
タグのすぐ後に1つだけ入れます(1つしか入れちゃダメ!)。そして、このcaption
要素にテーブルの短い説明を入れます。以下、コードの例です。
<table>
<caption>テーブルの短い説明</caption>
<tr>
<th>見出し1</th>
<th>見出し2</th>
<th>見出し3</th>
</tr>
<tr>
<td>データ</td>
<td>データ</td>
<td>データ</td>
</tr>
</table>
表示例
上のソースがレンダリングされると以下のように表示されます。CSSでスタイルは追加されています。
見出し1 | 見出し2 | 見出し3 |
---|---|---|
データ | データ | データ |
VoiceOverで読み上げると…
上のテーブルをVoiceOverで読み上げると以下のようになります。
テーブルの短い説明、表の開始位置です、2行、3列
caption
要素が入っていないテーブルだと、最初のセルが選択された際に、セルの内容から読み上げられます。
見出し1、行1、列1、表の開始位置です、2行、3列
ちょっとした差ですが、いきなり見出しが読み上げられるので、テーブルの読み上げが始まったことがわかりづらいです。やっぱりcaption
要素またはテーブルの前に説明が入っていた方が親切です。
summary属性について
複雑なテーブルの場合は、詳しい説明をsummary
属性を使って書くのが良いという情報が散見されますが、summary
属性はHTML5で廃止されているので使用は避けたほうが良さそうです(@bakeraさんにアドバイス いただきました)。代わりにaria-describedby
属性やfigure
要素を使った方法がW3Cウェブサイトで紹介 されています。この辺は、複雑なデータ・テーブルについての記事を書くときに一緒に紹介できればと思います。p
要素で説明を書いて、それをテーブルに紐づけるという方法です。
W3Cの仕様 では、summary
属性は非視覚メディア向けにテーブルの詳しい説明を書くために使うと説明されています。たとえば、複雑なテーブルで行や列がどのように構成され、それぞれのセルに何が入っているのかを詳しく説明するために使うものです。シンプルなテーブルではsummary
属性は必要ない場合が多いです。
また、caption
要素とsummary
属性は明確に役割を分けられているので、両方を使う場合は同じ情報をリピートしても意味がありません。
※ summary
属性はサポート状況がよくないので使わなくても良いという情報もありました。入れても無駄と考えるか、属性がサポートされる場合の付加情報として入れておくか。この辺は考え方次第ですね。
2. 表の見出しを指定する
th
要素を使って、行と列、または、行か列のヘッダーを指定します。一番シンプルな例だと以下のようになります。
<table>
<caption>テーブルの短い説明</caption>
<tr>
<th>見出し1</th>
<th>見出し2</th>
<th>見出し3</th>
</tr>
<tr>
<td>データ1</td>
<td>データ2</td>
<td>データ3</td>
</tr>
<tr>
<td>データ4</td>
<td>データ5</td>
<td>データ6</td>
</tr>
</table>
表示例
上のソースがレンダリングされると以下のように表示されます。CSSでスタイルは追加されています。
見出し1 | 見出し2 | 見出し3 |
---|---|---|
データ1 | データ2 | データ3 |
データ4 | データ5 | データ6 |
VoiceOverで読み上げると…
上に示したようにth
を使ってテーブルを組むとVoiceOverが見出しを認識してくれるので、列を移動した際にどの見出しの列にあるデータかわかるように「見出し」を先に読み上げてくれます。
たとえば「データ1」を読み上げてから「データ2」を選択すると「見出し2、データ2…」といったように読み上げられます。読み上げられているセルの見出しがわかりやすくて親切ですね。
行と列に見出しを入れる場合
では、行と列に見出しを入れるとどうなるか、もう少し現実味のある情報をテーブルに入れて見てみます。
<table>
<caption>メンバーの趣向</caption>
<tr>
<th>メンバー</th>
<th>好きなスポーツ</th>
<th>嫌いな食べ物</th>
</tr>
<tr>
<th>トム</th>
<td>野球</td>
<td>バナナ</td>
</tr>
<tr>
<th>ジョン</th>
<td>バスケットボール</td>
<td>ベーコン</td>
</tr>
</table>
表示例
上のソースがレンダリングされると以下のように表示されます。CSSでスタイルは追加されています。
メンバー | 好きなスポーツ | 嫌いな食べ物 |
---|---|---|
トム | 野球 | バナナ |
ジョン | バスケットボール | ベーコン |
VoiceOverで読み上げると…
VoiceOverを立ち上げて、テーブルの外にフォーカスがある状態でこのテーブルの「野球」を選択すると以下のように読み上げてくれます。
メンバーの趣向、トム、好きなスポーツ、野球、行2、列2
テーブルの外にフォーカスがあったので、まずはcaption
要素にあるテーブルの説明を読み上げて、見出しの「トム」と「好きなスポーツ」を読み上げてから、選択されたセルの内容「野球」を読み上げてくれます。
次に「ベーコン」を選択すると以下のように読み上げてくれます。
ジョン、嫌いな食べ物、ベーコン、行3、列3、表の終了位置です
次に「バスケットボール」を選択すると以下のように読み上げてくれます。
好きなスポーツ、バスケットボール、行3、列2
スクリーンリーダーがコンテキストを理解して、必要ない見出しを省略してくれるんですね。たとえばもっと大きなテーブルだったら、同じ列を読み上げてるのに毎回「ジョン」と言われても鬱陶しいですよね。
th
要素で見出しを入れておくと、スクリーンリーダーがいい感じに読み上げてくれるのでテーブルの内容がわかりやすくなります。逆に、見出しを入れないと、選択されたセルの内容が読まれるだけなのでテーブルを最初から読み上げないと理解するのが難しくなります。
3. セルを適切な見出しに紐付ける
列と行の両方にヘッダーがある場合、どちらのヘッダーかを指定するscope
属性を指定することが推奨されています。列のヘッダーにはscope="col"
を、行のヘッダーにはscope="row"
を入れます。
たとえば、以下のような記述になります。
<tr>
<th scope="col">列ヘッダー1</th>
<th scope="col">列ヘッダー2</th>
<th scope="col">列ヘッダー3</th>
</tr>
<tr>
<th scope="row">行ヘッダー1</th>
<td>データ</td>
<td>データ</td>
</tr>
ここで紹介しているシンプルなテーブルではscope
属性がなくてもVoiceOverがいい感じに読み上げてくれます。ただ、スクリーンリーダーはVoiceOverだけではないので、デフォルトで入れるように習慣づけておいた方が良さそうです。そうすれば、より複雑なテーブルのコーディングの際にも忘れることなく記述ができます。
以上が、アクセシビリティを考慮したデータ・テーブルのコーディングの3つの基本でした。
その他の注意点
情報を集めていて、僕が気になった点をあと3つほど書いておきます。
セルをスパン(統合)させる場合
セルをスパン(統合)させる場合でもscope
は適用されるとのことですが、スクリーンリーダーなどによっては複雑な構造のテーブルはサポートされていないそうなので、できるだけフラットでシンプルなテーブルの構築を心がけたほうが良さそうです。(テーブルだけじゃなくて、他の要素でもそうですね。シンプルイズベスト!)
ちなみに、より複雑な構造のテーブルについてはheaders
属性やid
属性を使った記述方法もあるらしいですが推奨されていないそうです。どうしても必要になってしまった場合のオプションとして覚えておけば良さそうです。
セルの幅指定について
ページが横スクロールしないようにするために、セルの幅は指定せずにブラウザのウィンドウ幅に合わせた自動的なレイアウトに任せるのが推奨されています。文字が拡大された場合なども考えてセルの高さも指定しないほうが良いです。
とはいえ、幅を指定しないとテーブルが見にくくなるケースもあります。なので、幅を指定する場合はパーセントなどの相対値を使うことが推奨されています。
theadやtbodyについて
thead
、tfoot
、tbody
はアクセシビリティ的には意味がないそうです。ただ、プリントするときにテーブルが複数ページに印刷される場合に、ヘッダーをリピートしてくれるそうです(要検証)。長いデータ・テーブルの場合、印刷される確率も上がりそうなので入れておくと親切ですね。
以上、アクセシビリティを考慮したデータ・テーブルのコーディングの基本についてまとめてみました。
Let’s have fun coding accessible data tables!
参考にした情報
以下のページを参考にさせてもらいました。
- WebAIM: Creating Accessible Tables – Data Tables
- Tables Concepts • Tables • WAI Web Accessibility Tutorials
- Tables in HTML documents
- <table>: 表要素 – HTML: HyperText Markup Language | MDN
summary属性の廃止について
更新情報
summary
属性についてのセクションを修正しました(2019/2/6)- 行と列の表記が逆になっていたので修正しました(2019/2/19)
2019年2月5日に公開され、2020年2月17日に更新された記事です。
About the author
「明日のウェブ制作に役立つアイディア」をテーマにこのブログを書いています。アメリカの大学を卒業後、ボストン近郊のウェブ制作会社に勤務。帰国後、東京のウェブ制作会社に勤務した後、ウェブ担当者として日英バイリンガルのサイト運営に携わる。詳しくはこちら。
ウェブ制作・ディレクション、ビデオを含むコンテンツ制作のお手伝い、執筆・翻訳のご依頼など、お気軽にご相談ください。いずれも日本語と英語で対応可能です。まずは、Mastodon @rriver@vivaldi.net 、Twitter @rriver 、またはFacebook までご連絡ください。