という訳で、Web Accessibility Advent Calender 2014 9日目の記事です。私も初日から公開される記事をずっと読んで勉強しておりますが、ここまで割と仕様とかガイドラインとか、あとは制作者としての気の持ちよう(?)とか、そういった話がずっと続いている気がしましたので、ここらでひとつ箸休めというか、実装に関する軽い話題をお送りしたいと思います。
さて、今ご覧のこのサイトですが、この数日ちょこちょことリニューアルを進めております。まだ制作途中で未完成な部分もありますが、概ねこんな感じにしようという部分はだいたい完了しましたので、見切り発車で公開しつつ直していこうかなという。まあその辺は本題ではないので後々ゆっくり触れるとして。
で、今回はロゴを PNG から SVG にしたんですが、まだもう少し IE8 からのアクセスがログに見られる以上、単純に img
要素ではなく object
要素で配置して、非対応な環境ではフォールバックとして PNG のロゴが表示されるようにしております。
最初に書いた HTML は次のようなものでした(いくつかの属性を省略して単純にしています)。
<object type="image/svg+xml" data="logo.svg">
<img src="logo.png" alt="JeffreyFrancesco.org" />
</object>
これで SVG に非対応な環境では入れ子になった img
要素がフォールバックとして表示されることになり、さらに画像が無効な場合は img
要素の代替テキストが表示されるはずです。ここまではいいんですが、ここでひとつ疑問が浮かびました。
「SVG に対応した環境では、img
の代替テキストはそのまま object
の代替テキストとして、スクリーンリーダーでそっちを読み上げてくれるのかしら?」と。
そこで、実際に VoiceOver をオンにして確認してみたんですが、読み上げられないんですよね…まあこれは当たり前といえば当たり前のような気もしますが、さらにいえば「画像」とも読み上げてくれなくて「フレーム」とか「空スクロール領域」とか言う訳です。これじゃ読み上げ環境ではもはや「そこに何かあるのは確かだけど、いったい何があるのか」すら分からない感じです。
そこで、スクリーンリーダーでも問題なく読んでくれるようにと、WAI-ARIA の属性を使ってみます。まず、読み上げる内容そのものは、aria-label
プロパティでサイト名を指定すればよさそうです。
<object type="image/svg+xml" data="logo.svg"
aria-label="JeffreyFrancesco.org">
<img src="logo.png" alt="JeffreyFrancesco.org" />
</object>
このようにしてみました。しかし、これだけで十分なのかと思いきや、うまくいきません…これは多分 object
要素は汎用の埋め込み要素なため、それだけでは何の役割を持っているのか情報が不十分なので読み上げられないのでは、と思いました。なので同時に role="img"
も指定して、「画像である」ということをはっきり伝えてやればよさそうです。
<object type="image/svg+xml" data="logo.svg"
aria-label="JeffreyFrancesco.org" role="img">
<img src="logo.png" alt="JeffreyFrancesco.org" />
</object>
ここまで書くことで、ようやく VoiceOver では「イメージ、JeffreyFrancesco.org」などと読み上げてくれました。まとめると、object
要素で配置した SVG をスクリーンリーダーにちゃんと認識させて読ませるには、
role="img"
を指定して、これが画像であることを伝えるaria-label
プロパティに代替テキスト(に当たる内容)を指定する
の2つは必要ということですね。
ところで、SVGのフォールバック画像を用意したときのブラウザのHTTPアクセス状況 | 富永日記帳というエントリによると、ここまでの object
と img
を入れ子にしたコードの場合、SVG に対応したブラウザでは、SVG 画像と PNG 画像の両方をリクエストをしてしまうという問題があるそうです。
ロゴひとつくらいなら微々たるものかもしれませんが、それでも通信コストを考えると、不要な画像のリクエストが発生するような状況はできれば避けたいところ。なので、今回のリニューアルで採用したコードは object
要素を入れ子にして使う方法です。
<object type="image/svg+xml" data="logo.svg">
<object type="image/png" data="logo.png">
<span>JeffreyFrancesco.org</span><!-- 代替テキストとして機能する -->
</object>
</object>
で、この場合もスクリーンリーダーで読ませるには、同様に role="img"
と aria-label
を指定…してもいいのですが、この場合最も内側の span
内のテキスト(代替テキストとして機能する)にすでにサイト名をベタに書いているのに、さらに両方の object
要素の aria-label
プロパティにサイト名を指定するのは、いささか冗長過ぎるような気もします。
なので、この場合は aria-label
ではなく aria-labelledby
プロパティを使うのがよさそうです。
<object type="image/svg+xml" data="logo.svg" role="img" aria-labelledby="sitename">
<object type="image/png" data="logo.png" role="img" aria-labelledby="sitename">
<span id="sitename">JeffreyFrancesco.org</span>
</object>
</object>
代替テキストとなる span
要素に適当な id
を与え、2つの object
要素には aria-labelledby
プロパティにその id
値を指定します。これで object
要素には span
要素内のテキストがラベルとして関連付けられ、先ほどの例と同様にそのテキストが読み上げられるようになります。まあ、どちらにしてもまったく同じ内容の属性を複数回書かないといけないのには違いないですが、3回書くよりは2回の方がまだマシだということで。
という訳で、今回は SVG 画像の配置に object
要素を使った場合のスクリーンリーダー対応を考えてみました。あと数年もすれば IE8 も Android2.3 も完全無視してよくなるレベルになるでしょうし、そうなれば普通に img
要素で問題ないですから、過渡期のテクニックであるとは思います。
…箸休めにしては長い文章だし、9日目をアップする前に10日目の方がすでにアップしてるという残念なことに。涙