前回の「アクセシビリティを考慮したデータ・テーブルのコーディングやってますか?(基本編)」の続きで、今回はもう少し複雑なテーブルについて(の考察を)まとめてみます。具体的に言うと行と列をスパンさせる場合のコーディングのやり方です。そもそも複雑なテーブルはシンプルなものに置き換えるという考えをベースにしつつ、列をスパンさせる場合のcolgroup
と、行をスパンさせる場合のrowgroup
+ tbody
を使ったコーディングのやり方を整理してみました。
それ、本当に役に立つの?
はじめにネタばらし的に書いてしまうと、実は今回紹介するデータ・テーブルの例では、colgroup
やrowgroup
を使っても使わなくてもVoiceOverでの読み上げに違いがありませんでした。ググると出てくるid
とheaders
属性を使うやり方も試してみましたが、こちらも読み上げに変わりはありませんでした(id
とheaders
属性の使用はソースが煩雑になってしまってあまり現実的ではないです)。
なので「これって本当に役に立つのかな?」という疑問が残っています。
でも、テーブルの構造をソースコードで明示しておくことには意味があると思うので、基本的なコーディングのやり方くらいは覚えておこうと思います。ソースコードを読み取って解釈するのはVoiceOverだけじゃないですし。複雑なテーブルにせざるを得ない状況(クライアントの要望とか?)もあると思います。
ちょっと複雑なデータ・テーブルのコーディング
W3Cのウェブアクセシビリティ・チュートリアル の内容をもとに、自分なりに検証して必要だと思う内容を整理してみました。
今回まとめたのは以下の2つのコーディングのやり方です。
実は、この「ちょっと複雑」というところがキモで、これ以上複雑な構造のテーブルは使わない方が良いと考えています。複雑なテーブルはユニバーサルにわかりやすくするのが困難なので、そもそもの構造を見直すのが得策だと思うからです。もちろん、目的によって判断基準は違ってきますが、より多くのユーザに、よりわかりやすく情報を提供したいのであれば、複雑な構造のデータ・テーブルはシンプルに再構成するなどの工夫をすべきです。
見出し列をグルーピングするcolgroupの使い方
まずは、列をスパンさせてグルーピングする場合のコーディングのやり方です。以下のようなテーブルのコーディングです。
食べ物 | スポーツ | |||
---|---|---|---|---|
トマト | ピーマン | 野球 | 柔道 | |
トム | 好き | 嫌い | 嫌い | 好き |
ジョン | 嫌い | 好き | 嫌い | 好き |
ソースコード
全体のソースコードは以下の通りです。
<table>
<caption>メンバーの好き嫌い</caption>
<col>
<colgroup span="2"></colgroup>
<colgroup span="2"></colgroup>
<tr>
<th rowspan="2"> </th>
<th colspan="2" scope="colgroup">食べ物</th>
<th colspan="2" scope="colgroup">スポーツ</th>
</tr>
<tr>
<th scope="col">トマト</th>
<th scope="col">ピーマン</th>
<th scope="col">野球</th>
<th scope="col">柔道</th>
</tr>
<tr>
<th scope="row">トム</th>
<td>好き</td>
<td>嫌い</td>
<td>嫌い</td>
<td>好き</td>
</tr>
<tr>
<th scope="row">ジョン</th>
<td>嫌い</td>
<td>好き</td>
<td>嫌い</td>
<td>好き</td>
</tr>
</table>
コーディングの要点
コーディングの要点は2つあります。
colgroup
要素で構造を定義scope
属性でグルーピングした見出しと列をひもづける
それぞれ見ていきましょう。
1. colgroup要素で構造を定義
まず、col
とcolgroup
要素を使って列のグループ構成をtable
タグのすぐ下に定義します。1つのセルをcol
、スパンする列をcolgroup
要素とspan
属性を使って記述します。スパンさせるセルの数も含め、合計が見出しのセルの数の合計と同じなるようにします。
<table>
<caption>メンバーの好き嫌い</caption>
<col>
<colgroup span="2"></colgroup>
<colgroup span="2"></colgroup>
<!-- 略 -->
2. scopeでグルーピングした見出しと列をひもづける
scope
属性を使って見出しと列、見出しと行をひもづけます。まずは、scope="colgroup"
でグルーピングした列とcolgroup
要素をひもづけます。
<!-- 略 -->
<col>
<colgroup span="2"></colgroup>
<colgroup span="2"></colgroup>
<tr>
<th rowspan="2"> </th>
<th colspan="2" scope="colgroup">食べ物</th>
<th colspan="2" scope="colgroup">スポーツ</th>
</tr>
<!-- 略 -->
それから、scope="row"
で、行の見出しと行をひもづけます。
<!-- 略 -->
<tr>
<th scope="row">トム</th>
<td>好き</td>
<td>嫌い</td>
<td>嫌い</td>
<td>好き</td>
</tr>
<!-- 略 -->
以上で、スパンさせたテーブルの構造をHTMLで明示することができました。
VoiceOverで読み上げると…
たとえば、上述したサンプルのテーブルで「トマト」を選択するとVoiceOverでは以下のように読み上げられます。
メンバーの好き嫌い、食べ物、トマト、行2、列2
トマトが「食べ物」のグループに属することがわかっていいですね。
ただ、その下のセル(好き)を選択すると、「トム、食べ物、好き」としか読み上げられないので、テーブルの構造を頭の中で描けてないとトマトのことを言っているのかピーマンなのかわかりません。
これを考えると、以下のようにテーブルを2つに分けた方が親切かもしれません。データの比較は難しくなるかもしれませんが、内容の理解が難しくなるよりはましだと思います。
トマト | ピーマン | |
---|---|---|
トム | 好き | 嫌い |
ジョン | 嫌い | 好き |
野球 | 柔道 | |
---|---|---|
トム | 嫌い | 好き |
ジョン | 嫌い | 好き |
colgroupとscopeを入れない場合
ちなみに、colgroup
やscope
を入れないバージョンを作ってVoiceOverで読み上げてみたんですが、読み上げ内容に特に変わりありませんでした。他のスクリーンリーダーやデバイスだと変わるのっでしょうか?この辺は今後の調査課題です。
ヘッダー行のグルーピングをするtbodyとrowgroupの使い方
今度は行をスパンするデータ・テーブルのコーディングのやり方です。以下のようなテーブルのコーディングです。
商品名 | 色 | サイズ |
---|---|---|
パンタロン | 赤 | L、M、S |
青 | L、S、XS | |
緑 | XL、M、XS | |
コーデュロイ | 茶 | XL、M、S |
チャーコール | S、XS |
ソースコード
全体のソースコードは以下の通りです。
<table width="100%">
<caption>サンプル2: ボトムスの在庫</caption>
<thead>
<tr>
<th scope="col">商品名</th>
<th scope="col">色</th>
<th scope="col">サイズ</th>
</tr>
</thead>
<tbody>
<tr>
<th rowspan="3" scope="rowgroup">パンタロン</th>
<th scope="row">赤</th>
<td>L、M、S</td>
</tr>
<tr>
<th scope="row">青</th>
<td>L、S、XS</td>
</tr>
<tr>
<th scope="row">緑</th>
<td>XL、M、XS</td>
</tr>
</tbody>
<tbody>
<tr>
<th rowspan="2" scope="rowgroup">コーデュロイ</th>
<th scope="row">茶</th>
<td>XL、M、S</td>
</tr>
<tr>
<th scope="row">チャーコール</th>
<td>S、XS</td>
</tr>
</tbody>
</table>
要点は以下の2つです。
- tbodyでスパンした行をグルーピングする
- スパンした行にrowgroupを指定する
1. tbodyでスパンした行をグルーピングする
スパンした行を以下のようにtbody
要素を使ってグルーピングします。tbody
要素は1つのテーブルで複数回使っていいんですね。僕はてっきり1回だけだと思ってました。
<!-- 略 -->
<tbody>
<tr>
<th rowspan="3" scope="rowgroup">パンタロン</th>
<th scope="row">赤</th>
<td>L、M、S</td>
</tr>
<tr>
<th scope="row">青</th>
<td>L、S、XS</td>
</tr>
<tr>
<th scope="row">緑</th>
<td>XL、M、XS</td>
</tr>
</tbody>
<tbody>
<!-- 略 -->
</tbody>
<!-- 略 -->
2. スパンした行にrowgroupを指定する
次にスパンしたセルにscope
属性を使ってrowgroup
を指定します。
<!-- 略 -->
<th rowspan="3" scope="rowgroup">パンタロン</th>
<!-- 略 -->
これだけです!
VoiceOverで読み上げると…
たとえば、テーブルの外にフォーカスがある状態でパンタロンの青を選択すると以下のように読み上げてくれます。
ボトムスの在庫、パンタロン、色、青、行3、列2
ここまではわかりやすいですね。ところが、パンタロンの青のサイズ(L、S、XS)を選択すると、以下のように読み上げられます。
ボトムスの在庫、パンタロン、サイズ、L、S、XS、行3、列3
この読み上げだと、どの色のパンタロンなのかわからないですね。
テーブルを上から順番に読み上げていけば理解できるんですけどね。それでも、以下のようにテーブルを分割した方が親切かもしれません。
分割したテーブルの例
色 | サイズ |
---|---|
赤 | L、M、S |
青 | L、S、XS |
緑 | XL、M、XS |
色 | サイズ |
---|---|
茶 | XL、M、S |
チャーコール | S、XS |
さいごに
今回は、アクセシビリティを考慮したちょっと複雑なデータ・テーブルのコーディングのやり方をまとめてみました。結局、「本当に役に立つのか?」という疑問が残り、セルはスパンさせずにテーブルを分割した方が良さそうだという結論に至りました。
でも、colgroup
やrowgroup
などの基本的な使い方は覚えておきたいと思います。VoiceOver以外のスクリーンリーダーが、よりわかりやすく読み上げてくれるかもしれないですし、こうやってコーディングしておけば将来VoiceOverが進化した時に、読み上げ方が変わっているかもしれません。
colgroupやrowgroupを指定するコーディングは、それほど手間のかかることでもないですし、基本に忠実にコーディングしていこうと思います。
では、Enjoy making accessible tables!
2019年2月25日に公開され、2020年2月17日に更新された記事です。
About the author
「明日のウェブ制作に役立つアイディア」をテーマにこのブログを書いています。アメリカの大学を卒業後、ボストン近郊のウェブ制作会社に勤務。帰国後、東京のウェブ制作会社に勤務した後、ウェブ担当者として日英バイリンガルのサイト運営に携わる。詳しくはこちら。
ウェブ制作・ディレクション、ビデオを含むコンテンツ制作のお手伝い、執筆・翻訳のご依頼など、お気軽にご相談ください。いずれも日本語と英語で対応可能です。まずは、Mastodon @rriver@vivaldi.net 、Twitter @rriver 、またはFacebook までご連絡ください。