音声出力環境における擬似要素(::before, ::after)の内容(content)の読み上げについて

スクリーンリーダーや音声ブラウザなどの音声出力環境で::before擬似要素、::after擬似要素にcontentプロパティで生成した内容は多くのソフトウェアで読み上げることができます。使い方次第で、薬にも毒にもなりえます。読み上げることがないように制御したい場合は、aria-hiddentrueで設定するしか有効な方法がなく、制御できるのは対応しているものに限られます。

CSSの内容生成について

HTMLなどで作られた文書内に直接表現されないものを表現するためにCSSには擬似要素というセレクタが用意されてます。CSS2よりcontentプロパティを伴って文書中に内容を生成できる:before擬似要素と:after擬似要素が追加され、策定中のCSS3では、半角コロン(:)を1つ用いる擬似クラスのセレクタと区別できるように擬似要素については半角コロン(:)を2つ用いるように変更され、::before::afterと記述します。

ここでは::before擬似要素、::after擬似要素とCSS3仕様の半角コロン(:)を2つ用いた記述方法に統一して紹介するものとしますが、CSS3仕様の記法をIE8がサポートしていないことから後方互換への配慮のために、実用はCSS2仕様の半角コロン(:)1つだけを記述する方が用いられます。

CSSで生成した内容の読み上げについて

擬似要素の役割が文書内に直接表現されないものを表現するために用いるセレクタであるため、音声出力環境においては、擬似要素で生成された内容は読み上げることがないと思っていらっしゃるWeb制作者の方も多いのではないかと思われますが、手持ちの環境で試してみたところ、Windows対応オープンソース(無料)スクリーンリーダーNVDAとMac OSやiOSに標準搭載されているVoiceOver、AndroidアプリのTalkBackでは::before擬似要素、::after擬似要素にcontentプロパティで生成される内容は普通に読み上げることが確認できました。

ただし、NVDAのようにスクリーンリーダーの場合は、ソフトウェア同士の組み合わせに依って動作が異なり、NVDAはFirefoxで使用することが推奨されており、NVDA + Firefoxでは読み上げるが(NVDA + Chrome, NVDA + Operaも可)、NVDA + Internet Explorerだけ読み上げないといった結果になったため、CSSで生成した内容を読みげあげるのかどうかについては現在出回っている多くの音声出力環境のソフトウェアで読み上げることができると言えそうです。

略語のtitle属性の値を生成した場合

abbr:after { content : attr(title); }
......
<p>ウェブページを記述する際に一般的に用いられるマークアップ言語に
<abbr title="HyperText Markup Language">HTML</abbr>がある。</p>

abbr要素にあるtitle属性の内容は通常HTML文書中に表現されることのない内容ですが、それを:after擬似要素によってtitle属性の内容を生成しています。上記のように略語を示すabbr要素でtitle属性の値にその正式名称を記しており、加えて::after擬似要素にcontentプロパティでtitle属性の値を生成している場合、多くの音声出力環境でどのように読み上げるのでしょうか。

先述のとおり、contentプロパティで生成された内容は多くのソフトウェアで読み上げることができるので、abbr要素のtitle属性を音声出力環境が読み上げるのかがどうかが焦点となり、ここで想定される具合の悪い事態は、HyperText Markup Language HyperText Markup Languageのように重複して読み上げてしまうことです。

title属性について

title属性は1995年にIETFで制定されたHTML2.0からa要素に定義されており、1997年に勧告されたHTML4.0からは中心属性として全ての要素に指定することができるようになるなど、これだけ昔から非視覚環境も含めて補足情報として利用されることを期待して設けられてきたにもかかわらず、UA側でのサポートの強化(視覚ブラウザであればキーボード操作だけでツールチップを表示する、音声出力環境であればtitle属性がある場合に通知するなど)があまり進んでこなかった理由から、HTML5勧告時点(2014年10月28日)においてはtitle属性に頼ることが推奨されなくなっている、という謎な経歴をもつ属性です。

なお、まったくサポートの強化が進んでこなかったというわけではなく、IE11ではキーボード操作だけでツールチップを表示するようになったなど、UA側もtitle属性のサポートの強化を進めている動きはありました。

音声出力環境下におけるtitle属性の実態はというと、通常利用時ではどのソフトウェアも読み上げることはありません。フォーム関連の部品要素(input要素やselect要素など)であればフォーカス時にしっかりと読み上げるので手厚いサポート状況ですが、a要素のtitle属性はオプション設定欄から読み上げる設定にしているか、ホットキー(ショートカットキー)を読み上げ時に操作した場合にのみ読み上げるという対応にとどまり、それ以外の要素に設けられたtitle属性になると、JAWSという製品がオプション設定欄で略語を展開するという設定にしている場合にのみ読み上げるという状況で、ほぼ活用されていないことになります。詳しくは、以下のリンクから各スクリーンリーダーのtitle属性における対応状況を確認できます。

以上のtitle属性の状況を鑑みると、abbr要素でtitle属性の値にその正式名称を記しており、加えて::after擬似要素にcontentプロパティでtitle属性の値を生成している場合に重複して読み上げることになるかどうかは現時点では、JAWSにおいて複雑なオプション設定をしている場合に限られるので、心配はいらないと言えそうです。

UAのサポートの強化が進んでいないという理由からtitle属性に頼ることをHTML5勧告時点(2014年10月28日)においては推奨しないことになっていますが、それなりの普及・認知がある属性だけにこのまま見捨てられるのは惜しく、CSSの内容生成が視覚環境でも・非視覚環境においても活用されるようになれば、title属性も見直されるかもしれません。

読み上げ時の支援を高めるために用いる場合

パンくずリストを視覚的にも、音声出力環境においてもわかりやすくしてみましょう。なお、contentプロパティにASCII文字列以外を含める場合は、ブラウザが文字エンコーディングを誤って文字化けを起こす原因になるため(詳しくはcontentプロパティを参照)、以下のサンプルコードのように16進表記のUnicodeへエスケープして使うことが一般的です。

#breadcrumbs li::before {
  content : "\73FE\5728\4F4D\7F6E\306F";
   /*「現在位置は」と生成するが視覚環境では非表示に*/
  display : block;
  width : 0;
  height : 0;
  visibility : hidden;
}
#breadcrumbs li::after {
  content : "\3E";
   /*「から」と生成するが視覚環境では大なりの記号の背景を表示*/
  display : inline-block ;
  background-image : url(/img/gt-icon.gif);
  padding : 10px 0 0 10px;
  width : 0;
  height : 0;
  overflow : hidden ;
}
#breadcrumbs li + li::after {
  content : "\306E\4E2D\306B\3042\308B";
   /*「の中にある」と生成する*/
}
#breadcrumbs li:last-child::after {
  display : none;
   /*最後のリストは何も表示・生成しない*/
}
......
<div id="breadcrumbs">
<ul>
<li><a href="/">トップページ</a></li>
<li><a href="/about/">会社案内</a></li>
<li>会社概要</li>
</ul>
</div>

上記の部分は「現在位置は トップページ リンク から 会社案内 リンク の中にある 会社概要」と読み上げます。多くのサイトでパンくずリストには、その階層構造を視覚的に表現する目的で大なり(>)の記号がよく用いられます。視覚障碍を持つユーザにとっても、大なり(>)とリンクが連続する部分の読み上げがあると「パンくずリストかな?!」と認知するきっかけにはしてくれますが、改善の余地があるため、大なり(>)記号部分は背景画像で代用し、より認知しやすいように「から」や「の中にある」などの形で提供するとより良いのではないでしょうか。

最初に「現在位置」という内容を生成しておくことで一層読み上げ時の認知の支援につながります。逆にこれらの読み上げがなかったら「トップページ リンク 会社案内 リンク 会社概要」だけの読み上げになるのでパンくずリストかどうかの認知にも至らないことでしょう。

パンくずリストの例のように、他にもmain要素の最初に「ここから本文」、nav要素の最初に「ここからナビゲーション」といったコンテンツを認知しやすいように読み上げ時の支援を高める目的での利用方法は、HTMLを編集することなくCSSファイルひとつに書き加えるだけで簡単にサイト内の全ページに実装できるので実用的ではないでしょうか。

音声出力環境でのみ読み上げて、視覚環境では表示させたくないという用い方をしたい場合も、生成内容にdisplay : block; width : 0; heihgt : 0; visibility : hidden;などのスタイルを加えて、視覚的に隠すだけで済むので、HTMLを編集することなく簡単に実現できる点では優れてます。

アクセシビリティを阻害するような内容を生成してしまう場合

高解像度への対応などで、アイコンフォントを使いたい場合があります。アイコンフォントは、アルファベット1文字に1アイコンを割り当てる形になっており、CSSでアルファベットに割り当てられたアイコンを生成している場合、意味の通じないアルファベット1文字だけを読み上げることになります。アルファベット1文字に1アイコンの欠点を補おうものとしてリガチャー(合字)で単語1語に1アイコンを割り当てた方法がありますが、リガチャー(合字)であっても単語とラベルの内容を重複して読み上げることになります。

@font-face{
  font-family : "icon-font";
  src : ... ;
}
nav a:before{
  font-family : "icon-font";
  font-feature-settings : "liga" 1;
  content : attr(class);
  ...
}
......
<nav>
<ul>
<li><a href="/news/" class="news">お知らせ</a></li>
<li><a href="/product/" class="product">製品紹介</a></li>
<li><a href="/about/" class="about">会社案内</a></li>
<li><a href="/recruit/" class="recruit">採用情報</a></li>
</ul>
</nav>

上記の部分は「ニュース お知らせ リンク プロダクト 製品紹介 リンク アバウト 会社案内 リンク リクルート 採用情報 リンク」と読み上げます。リガチャー(合字)で言語が異なる同じ意味のラベルを読み上げることになり、制作者としては意図しない読み上げの状況を作りだしてしまっているため、このような事態は避けたいところです。

CSSで生成した内容を読み上げないようにする

CSSで生成している内容なので、CSSの音声出力に関するプロパティで読み上げないように制御することができるのではないかと考えられるかもしれません。

nav a:before{
  font-family : "icon-font";
  font-feature-settings : "liga" 1 ;
  content : attr(class);
  ...
  speak : none;
}

これで読み上げないように制御できているのかというと、残念ながらCSSの音声出力に関するプロパティではまったく制御できません。音声出力に関するプロパティは、そもそもが音声ブラウザ向けに定義された仕様のため、IEやFirefox, Chromeなどの視覚ブラウザは一切サポートしていません(今後もサポートすることはないでしょう)。OSごとスクリーン上のあらゆる情報を読み上げるスクリーンリーダーに対し、音声ブラウザは単独で視覚障碍者向けの表示と読み上げ機能を提供をするソフトウェアで、現在も開発中のものはNetReaderぐらいで、他の製品は開発・販売ともに終了しています。NetReaderにおいても音声出力に関するプロパティはサポートしていません。

では、読み上げないように制御できる手段はないのかというと、高度化・複雑化するWebのさまざまな問題を解消する技術仕様として2008年から策定が進められ、2014年3月20日付で1.0版が勧告されたWAI-ARIAに対応することで、CSSで生成した内容を読み上げないようにすることができます。これにはHTMLそのものの編集が必要になります。

@font-face{
  font-family : "icon-font";
  src : ... ;
}
nav a span:before{
  font-family : "icon-font";
  font-feature-settings : "liga" 1 ;
  content : attr(class);
  ...
}
......<nav>
<ul>
<li><a href="/news/"><span class="news" aria-hidden="true"></span>お知らせ</a></li>
<li><a href="/product/"><span class="product" aria-hidden="true"></span>製品紹介</a></li>
<li><a href="/about/"><span class="about" aria-hidden="true"></span>会社案内</a></li>
<li><a href="/recruit/"><span class="recruit" aria-hidden="true"></span>採用情報</a></li>
</ul>
</nav>

このように空要素を記述せざるをえないことには抵抗を感じますが、現時点で唯一の次善策となります。aria-hiddenは支援技術を提供するソフトウェアにおいて表示・非表示を制御するもので、スクリーンリーダーの場合はaria-hidden="true"を設けることで読み飛ばすように制御することができます。ただし、その制御ができるのは、aria-hiddenをサポートしているソフトウェアに限られます。そのため問題は、どれぐらいのソフトウェアがサポートしているかのというとことになりますが、手持ちの環境で試すことができるWindowsのNVDA、Mac OS・iOSのVoiceOver、AndroidアプリのTalkBackでは、ちゃんと読み飛ばしていることが確認できました。WAI-ARIAへの対応は比較的積極に進んでいることから、大半のソフトウェアでサポートできていると考えられます。

CSSで生成する内容と音声出力環境における総括

  • スクリーンリーダーや音声ブラウザなどの音声出力環境で::before擬似要素、::after擬似要素にcontentプロパティで生成した内容は多くのソフトウェアで読み上げることができる。
  • 使い方次第では現状まったく活用できていないtitle属性を、視覚環境でも・非視覚環境でも活かせるように一役買ってくれるかもしれない。
  • HTMLを編集することなく、CSSファイルひとつを編集するだけで簡単に全ページの読み上げ時の支援を高めるために実用的に使えるかもしれない。
  • 音声出力環境のみ読み上げ、視覚環境では表示させたくないという用い方をしたい場合、(WAI-ARIAには支援技術を提供するソフトウェアにのみ認識できるラベルを付けられるaria-labelがあるが、)生成内容にdisplay : block; width : 0; heihgt : 0; visibility : hidden;などのスタイルを加えて、視覚的に隠してしまうだけで済むので、HTMLを編集する必要がなく簡単に実現できる点では優れている。
  • CSSで生成した内容を画面上は表示するが、音声出力環境で読み上げることがないように制御したい場合、aria-hiddentrueで設定することしか有効な方法はなく、制御できるのはサポートしているものに限られる。

WCAG2.0における不適合事例

補足事項として、WCAG2.0に以下のチェック項目を満たせないものは、不適合として事例が挙げられています。

F87: 達成基準 1.3.1 の不適合事例 - CSSの :before や :after 疑似要素及び 'content' プロパティを用いて、装飾目的ではないコンテンツを挿入している
  1. ::before::after の疑似要素及び content プロパティを用いて挿入されている全てのコンテンツを探し出す。
  2. コンテンツは、装飾を目的にしたものである。
  3. 挿入されたコンテンツが装飾を目的にしたものではない場合、その情報が支援技術に対して提供されており、CSSをオフにした際にも入手可能である。

ただ、視覚障碍を持つユーザがJavaScriptやCSSをオフにしているというのは迷信に過ぎず、わざわざ制作者のCSSをオフにして利用している可能性は限りなく低いと言えます。なぜなら、制作者のCSSでは、display : none;で余計なものを読み上げることがないように配慮するためのものでもあるのですから、制作者のCSSまでオフにした上で、アクセシビリティがサポートされているウェブサイトとなると厳しすぎませんかね...もちろん、CSSがオフの際でも情報が入手可能になっているに越したことがないのは確かでしょう。アクセシビリティは本当奥が深くて、難しい。

本記事に頂いたフィードバックのご紹介

本記事に対していただいているフィードバックです。あわせてご参照ください。私自身、フィードバックをいただくことで自分の未熟な点に気付け、たいへん勉強になっております。御礼申し上げます。

Updated / Published