お使いのブラウザは最新版ではありません。最新のブラウザでご覧ください。

CNET Japan ブログ

【アクセシビリティ】 ブロック・スキップの“決定版”を考える (ナビゲーション・スキップ)

2009/03/09 00:52
  • このエントリーをはてなブックマークに追加

ミキ・オキタWebClip ウェブデザインのニュース

この記事のトピック

こんにちは。“時代の3歩先をねらうWeb屋さん”ミキ・オキタです。
このブログ「WebClip ウェブデザインのニュース」では、Webデザイン・Webマーケティングの話題をお届けしています。

ブロック・スキップの“決定版”をつくる。

Webアクセシビリティのテクニックに“ブロック・スキップ”(注1)がある。
“ナビゲーション・スキップ”“スキップ・リンク”“オーラル・ナビゲーション”と呼ばれることもある。

“ブロック・スキップ”とは、通常のブラウザ (Internet ExplorerやFirefoxなど) では描画されず、音声ブラウザ(注2)のみ読み上げられるページ内リンクを指す。多くの場合、グローバルナビゲーションやローカルナビゲーションを飛ばして、本文へ飛べるようにするために設置する。

音声ブラウザはHTMLを冒頭から読み上げていく。
グローバルナビゲーションのように各ページ共通の要素を、毎回読み上げていくと利用者が疲れてしまう。それを避けるため、ブロック・スキップでHTML冒頭から本文へ即ジャンプできるようにする。
Webアクセシビリティ規格 JIS X 8341-3:2004 5.3.hに示された要件だ。JIS X 8341-3:2009 (改正草案) では、7.2.4.1に示されている。

このブロック・スキップだが、実は、どのようにHTML/CSSのコーディングをするべきか、スタンダードがない。
僕も何度も悩まされてきた。
そこで、ブロック・スキップはどのような実装が適切なのか、突き詰めてみた。
検証環境は、PC-Talker XP + Internet Explorer 7、IBM ホームページ・リーダー ver 3.04 で行った。

(注1) Webアクセシビリティ規格 JIS X 8341-3:2009 草案では“ブロック・スキップ”表記になっている。本記事ではこれに倣い“ブロック・スキップ”で統一する。

(注2) 本記事では、冗長になるのを避けるため、音声ブラウザとスクリーンリーダを“音声ブラウザ”という表記で包括した。

ブロック・スキップのよくあるパターン。

ブロック・スキップはさまざまなコーディング方法があるが、大雑把に、主要なものは以下の2パターンだ。

【パターンA: JIS X 8341-3:2004 例示パターン】

1x1ピクセルの透過gifを設置し、alt属性に音声ブラウザ向けのテキストを入れる方法。
Webアクセシビリティ規格 JIS X 8341-3:2004 の附属書1 2.3.fに、具体的なコーディングの例示があるので、公的な根拠を示せる。
spacer.gifは1x1ピクセルの透過gifだ。

例:

<a href="#content"><img src="spacer.gif" width="1" height="1" border="0" alt="本文へジャンプ"></a>
・・・読み飛ばしたい部分・・・
<a name="content" id="content"><img src="spacer.gif" width="1" height="1" border="0" alt="ここから本文です"></a>

次のようなメリットとデメリットがある。

  • メリット:Webアクセシビリティ規格の例示として、採用する根拠が明確。
  • デメリット:1ピクセルとはいえ、レイアウトに影響する。音声ブラウザのためだけに画像を配置するため、構造化されたHTMLとは呼びづらい。

【パターンB: OffScreenパターン】

音声ブラウザ向けのテキストをCSSで画面外に飛ばす方法。「OffScreen」と呼ばれるテクニックだ。

例:

div.navihidden {
 position:absolute;
 margin-left:-9999px;
}

<div class="navihidden"><a href="#content">本文へジャンプ</a></div>
・・・読み飛ばしたい部分・・・
<div class="navihidden"><a name="content" id="content">ここから本文です</a></div>

  • メリット:世間一般で多く使われている。CSSでテキストを画面外に飛ばすだけなので、余計な画像を配置する必要がなく、構造化されたHTMLにしやすい。
  • デメリット:検索エンジンの検索結果にブロック・スキップに含まれた文字列(「本文へジャンプ」など)が出てしまうことがある。検索エンジン対策として好ましくない。

国内でよく見かけるのは、この2パターン。ほかにも、総務省実証実験「みんなのウェブ」などで使われているパターン( width:0; height:0; )など、バリエーションを挙げればきりがない。

では、ブロック・スキップは、どのようにコーディングするのが良いだろうか。

【パターンB OffScreenパターン】の問題。

僕の経験的には、一番見かけるブロック・スキップは【パターンB: OffScreenパターン】だ。
CSSでテキストを画面外に飛ばす方法。HTMLの構造も美しい。

しかし【パターンB: OffScreenパターン】は欠点がある。
[画像1]を見て欲しい。

[画像1 クリックで拡大]
(注3)

検索エンジンの検索結果にブロック・スキップの文字列(「ここからページ共通メニューです・・・」)が出てしまっている。
運が悪い場合、100文字程度しか表示されない説明文の大半がブロック・スキップの文字列で埋まるケースもある。

検索結果の説明文は、訪問者を誘導するための大切な部分だ。
【パターンB: OffScreenパターン】は、思わぬところで、検索エンジン対策の“邪魔”になることがある。

検索エンジン対策の“邪魔”になりかねないブロック・スキップは、企業として受け入れられづらい。
また、Web制作会社も、検索エンジン対策の“邪魔”になりかねない提案はしづらいだろう。

検索結果に表示されることを避けるには、画像のalt属性に文字列などを入れることが好ましい。
この点を考慮すると、【パターンB: OffScreenパターン】は選択肢として選びづらい。

(注3) [画像1]はたまたま見つけた事例で、検索キーワードに深い意図はない。念のため。

【パターンA: JIS X 8341-3:2004 例示パターン】 におけるPC-Talkerの問題

では、【パターンA: JIS X 8341-3:2004 例示パターン】で決定かというと、そんなに簡単ではない。

ブロック・スキップは、主に音声ブラウザに配慮する目的で設置する。逆に言うと、音声ブラウザで実際に動作しないと意味がない。

視覚障害者のパソコン・インターネット・携帯電話利用状況調査2007」によると、日本の音声ブラウザのシェアで、上位トップは『PC-Talker』と『IBM ホームページ・リーダー (以下、HPR)』。このふたつには対応しておきたい (シェア第3位の『95Reader』はページ内リンクが動作しないので対象外)。

ところが、【パターンA: JIS X 8341-3:2004 例示パターン】は、そのままでは、PC-Talkerで動作しない。何も読み上げない。

PC-Talkerには、alt属性の読み上げにバグがある。a要素がらみで世間的によく知られているバグだ。

【バグ1.PC-Talkerは、a要素に含まれる画像のalt属性を読み上げない】

PC-Talkerは、a要素の子要素となる画像のalt属性を読み上げない。
正しく言うと、PC-Talkerは、a要素の子要素に画像が存在したとき、画像のalt属性の代わりに、親になるa要素のtitle属性を読み上げる。
先ほどの【パターンA: JIS X 8341-3:2004 例示パターン】で例示したソースコードでいうと、a要素にtitle属性は設定されていない。そのため、PC-Talkerは“空のtitle要素を読み上げる”=“何も読み上げない”という挙動を見せる。

もう少し具体的に説明する。
例えば、以下のソースコード。

例:

<a href="#content" title="ここはa要素のtitle属性"><img src="spacer.gif" width="1" height="1" border="0" alt="ここは画像のalt属性"></a>

PC-Talkerは「ここは画像のalt属性」を無視して「ここはa要素のtitle属性」だけを読み上げる。

対照的に、HPRは画像のalt属性のみを読み上げる。「ここはa要素のtitle属性」を無視して「ここは画像のalt属性」と読み上げる。

PC-Talkerでも、HPRでも、読み上げに対応するためには、次のようにソースコードを書く必要がある。

例:

<a href="#content" title="本文へジャンプ"><img src="spacer.gif" width="1" height="1" border="0" alt="本文へジャンプ"></a>
・・・読み飛ばしたい部分・・・
<a name="content" id="content"></a><img src="spacer.gif" width="1" height="1" border="0" alt="ここから本文です">

コード前半部のリンク元はa要素にPC-Talker用のtitle属性を設定し、画像にもHPR用のalt属性を設定する。コード後半部のリンク先は、a要素から画像を出してしまう。
PC-Talkerは、href属性を伴わないa要素、つまりリンクを持たないa要素であっても、PC-Talkerは「リンク」扱いで読み上げてしまう。これを回避するため、href属性を伴わないa要素に画像を入れない。

・・・念のため言うと、これはバッドノウハウを多分に含んでいる。ブラウザ個別の仕様に依存した実装に踏み込んでいる。
Webアクセシビリティは、本来、Web標準に準拠した作成が前提であるべきだ。
もちろん、実際に利用できなければWebアクセシビリティの確保にはならない。悩ましいところだ。

レイアウトへの影響を失くす。

ここまで書いたことを解決すれば、とりあえず、PC-Talkerでも、HPRでも、同じように読み上げられる。

しかし、次にレイアウトの問題がある。
1x1ピクセルの画像を配置するため、若干であるが、レイアウトに影響を与えてしまう。
CSSでぴっちりとしたレイアウトを組んだときなど、1ピクセルが原因でレイアウト崩れを起こすこともある。
レイアウトへの影響は、極力、減らしたい。

そこで、【パターンB: OffScreenパターン】のノウハウを、【パターンA: JIS X 8341-3:2004 例示パターン】に応用し、1x1ピクセルの画像を画面外に飛ばしてしまう。具体的には次のようにする。

例:

div.navihidden {
 position:absolute;
 margin-left:-9999px;
}

<div class="navihidden"><a href="#content" title="本文へジャンプ"><img src="spacer.gif" width="1" height="1" border="0" alt="本文へジャンプ"></a></div>
・・・読み飛ばしたい部分・・・
<div class="navihidden"><a name="content" id="content"></a><img src="spacer.gif" width="1" height="1" border="0" alt="ここから本文です"></div>

これでブロック・スキップがレイアウトに影響を与えなくなる。

画面から隠すだけなら、CSSでdisplay:none;やvisibility:hidden;でよいと思うかもしれない。実際、そういうコーディングを見かけることもある。

しかし、実はここにも問題がある。display:none;は、HPRでは読み上げられないのだ。
visibility:hidden;はHPRとPC-Talkerに限っては大丈夫だが、一部の音声ブラウザでやはり読み上げの対象にならない。
そのため、音声ブラウザでも読み上げられるためには、【パターンB: OffScreenパターン】のテクニックを使用する必要がある。

これでOKだろうか?
いやいや、まだ問題は続く。

PC-Talkerのページ内リンクには更なるバグがある。

【バグ2.PC-Talkerは、ページ内リンクが正しく動作しない】

もうひとつ、PC-Talkerのページ内リンクには、Internet Explorerのバグに由来する更なるバグがある。
PC-Talkerは、ページ内リンクをクリックしても、リンク先のアンカーにジャンプしないケースが存在する。ページ内リンクが動作しないのだ。ブロック・スキップの意味がない。

PC-Talkerは、リンク先となるa要素にname属性のみの場合は正しく動作する。
しかし、id属性のみの場合、またはname属性とid属性を両方記載した場合、うまくジャンプしない。

ややこしいので、単純化したソースコードで説明しよう。いずれも動作しない例だ。

例 (このソースコードは正しく動作しない):

<a href="#content">本文へジャンプ</a>
・・・読み飛ばしたい部分・・・
<a name="content" id="content">ここから本文です</a>

例 (このソースコードも正しく動作しない):

<a href="#content">本文へジャンプ</a>
・・・読み飛ばしたい部分・・・
<a id="content">ここから本文です</a>

もし、正しく動作させようと思えば、次のように書くことになる。

例:

<a href="#content">本文へジャンプ</a>
・・・読み飛ばしたい部分・・・
<a name="content">ここから本文です</a>

・・・なんというバッドノウハウ。
name属性は HTML 4.01 でも廃止方向にある。本来はid属性でコーディングするのが望ましく、name属性とid属性の両方を記載するのは“移行措置”だと、W3Cの HTML 4.01 仕様書にも記載がある。しかし、PC-Talkerでは、name属性でしか正しく動作しない。

いずれにせよ、対応策はわかった。これを先ほどのブロック・スキップに組み込めばよいだろうか。

さらに問題は続く。

上記を踏まえて、先ほどのブロック・スキップをname属性だけに修正しても、残念ながら、動作しない。

例 (このソースコードは正しく動作しない):

div.navihidden {
 position:absolute;
 margin-left:-9999px;
}

<div class="navihidden"><a href="#content" title="本文へジャンプ"><img src="spacer.gif" width="1" height="1" border="0" alt="本文へジャンプ"></a></div>
・・・読み飛ばしたい部分・・・
<div class="navihidden"><a name="content"></a><img src="spacer.gif" width="1" height="1" border="0" alt="ここから本文です"></div>

PC-Talkerのページ内リンクの不具合は、複数の要因が絡み合っている。
id属性・name属性のバグに加えて、まだあるのだ。

PC-Talkerは、widthやheight、またはposition:absolute;を設定した“div要素”に含まれるアンカーのジャンプは動作しない。

たとえば、次のようなケースで、既に動作しない。

例 (このソースコードは正しく動作しない):

div#wrapper {
 width:955px;
}

<body>
<div id="wrapper">

<a href="#content">本文へジャンプ</a>
・・・読み飛ばしたい部分・・・
<a name="content">ここから本文です</a>

</div>
</body>

勘の鋭い方ならもうご理解されたかもしれない。
“全体をかこむdiv要素の中には、ブロック・スキップは設置できない”
現実味のない要求事項だ。

ちなみに、この問題が発生するのはdiv要素だけ。
ためしにdiv要素をp要素に置き換えてみると、正しく動作する。
とはいえ、p要素に置き換えて解決する問題ではない。

ここまできてお手上げか・・・。空を仰いだ。

しかし、この不具合を回避する方法があった。

PC-Talkerのページ内リンクの特効薬。

PC-Talkerのページ内リンクの不具合は、リンク先のアンカーが、table要素のなかにあるとき、正常に動作するようになる。

例:

div#wrapper {
 width:955px;
}

<body>
<div id="wrapper">

<a href="#content">本文へジャンプ</a>
・・・読み飛ばしたい部分・・・
<table><tr><td><a name="content">ここから本文です</a></td></tr></table>

</div>
</body>

かつて asahi.com (朝日新聞) で使われていた手法だという。

table要素に入れれば、このブロック・スキップがdiv要素のなかに設置されても正しく動作する。ただし、PC-Talkerのためだけに、意味のないtable要素を設置することになる。バッドノウハウ。

ちなみに、table要素に入れてしまえば、id属性とname属性の併記でも正しく動作するようになる。id属性だけでは、ジャンプはするものの、読み上げがそこで停止してしまう。id属性単独では使えない。

また、table要素をそのまま設置すると、当然のことながら、レイアウトに影響を与える。OffScreenを使用してtable要素を画面外に飛ばす必要がある。

このtable要素を使ったコーディングについては、書籍『Webアクセシビリティ 標準準拠でアクセシブルなサイトを構築/管理するための考え方と実践』7章 (P.230) に、簡単な解説が載っている。

まとめ:ブロック・スキップの“決定版”

以上をまとめると、次のソースコードになる。

例 (ブロック・スキップの“決定版”):

div.navihidden {
 position:absolute;
 margin-left:-9999px;
}

<div class="navihidden"><a href="#content" title="本文へジャンプ"><img src="spacer.gif" width="1" height="1" border="0" alt="本文へジャンプ"></a></div>
・・・読み飛ばしたい部分・・・
<table class="navihidden"><tr><td><a name="content"></a><img src="spacer.gif" width="1" height="1" border="0" alt="ここから本文です"></td></tr></table>

前半部のリンク元は、PC-Talker用title属性と、HPR用alt属性を個別に設置。
後半部のリンク先はPC-Talkerが正しく動作するようにtable要素を使用し、レイアウトに影響を与えないように画面外に飛ばす。

これで、PC-Talkerでも、HPRでも、正しく動作する。検索エンジンの検索結果にも表示されない。

本記事では、これをブロック・スキップの“決定版”としたい。しかし、説明してきたように、バッドノウハウを多分に含んでいる。このとおり実装するかどうかはご検討いただきたい。

ブロック・スキップは、アクセシビリティ対応で必ずと言っていいほど出てくる、特徴的なテクニックだ。避けては通れない。状況に応じて最適のブロック・スキップを実装したい。

なお、この記事は、以下のページを参考に作成した。

【参考リンク】

PC-TalkerXP読み上げチェック - eye's, Inc.

リンクテキストとアクセシビリティとスクリーンリーダーの動作 - TRANS [hatena]

各スクリーンリーダー読み上げチェック - eye's, Inc.

a要素とtitle属性 - ミツエーリンクス Web標準Blog

ウェブアクセシビリティ入門 第7号

記事の間違い - takayanの雑記帳

ご意見・お問合せ - コル企画 (ページ下部)

PC-Talkerでページ内リンクが有効になる技 - Webアクセシビリティについての覚書

この記事に拍手する

はてなブックマークに追加はてなブックマークに追加

※このエントリは CNET Japan ブロガーにより投稿されたものです。朝日インタラクティブ および CNET Japan 編集部の見解・意向を示すものではありません。
運営事務局に問題を報告

最新ブログエントリー