JeffreyFrancesco.org 公開日 タグ Tag Permalink 現在地 Facebook page Twitter RSS feed

という訳で、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アクセス状況 | 富永日記帳というエントリによると、ここまでの objectimg を入れ子にしたコードの場合、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日目の方がすでにアップしてるという残念なことに。涙