WCAG 2.0 達成方法集

Skip to Content (Press Enter)

クライアントサイド・スクリプトの達成方法

このウェブページは、「WCAG 2.0達成方法集 : WCAG 2.0の達成方法と失敗例」におけるクライアントサイド・スクリプトの達成方法を掲載している。ウェブコンテンツ技術特有の達成方法は、「一般(General)」の達成方法に取って代わるものではない。コンテンツ制作者は適合に向けて作業する際には、「一般(General)」の達成方法とウェブコンテンツ技術特有の達成方法の双方を考慮に入れる必要がある。

ウェブコンテンツ技術特有の達成方法は、あらゆる状況で WCAG 2.0 の達成基準と適合要件を満たすコンテンツを作るために使うことができる技術を指しているわけではない。 コンテンツ制作者はその技術の限界に注意を払い、障害のある人にアクセシブルな方法でコンテンツを提供す必要がある。

達成方法についての情報は、WCAG 2.0 達成方法集のイントロダクションを参照のこと。他のウェブコンテンツ技術の達成方法一覧については、目次を参照のこと。




SCR1: 利用者が初期設定の制限時間を延長できるようにする

適用(対象)

クライアントサイドスクリプトによりコントロールされた制限時間。

これは、次の達成基準に関連する達成方法である:

解説

この達成方法の目的は、スクリプトがデフォルトの制限時間のある機能を提供する際、その時間を延長するメカニズムを提供することによって、利用者がデフォルトの制限時間を延長できるようにすることである。利用者がより長い制限時間を要求できるようにするために、利用者がより長い制限時間を入力できる、又は より多くの時間を必要としていることを示す(例えば)フォームをスクリプトが提供することができる。制限時間が切れそうであることを利用者に警告する場合(SCR16: 制限時間が切れようとしていることを利用者に警告するスクリプトを提供するを参照)、このフォームを警告のダイアログから利用可能にする。どれぐらいの追加時間が必要かを示すことができるようにするか、繰り返し制限時間を延長できるようにすることによって、利用者はデフォルトの制限時間を少なくとも10倍延長することができる。

事例

  • ウェブページに最新の株式市場のデータがあり、定期的に更新されている。利用者が最初の更新の前に警告を受けたとき、利用者には更新の間隔を延長するための選択肢が提供されている。

  • オンラインチェスゲームにおいて、各プレーヤーはそれぞれの動きが終わるまでの制限時間が与えられている。動かせる時間がほとんど終わりであるという警告をプレーヤーが受けたとき、利用者には時間を増やすための選択肢が提供されている。

参考リソース

この参考リソースは、あくまでも情報提供のみが目的であり、推薦などを意味するものではない。

  1. PHPBuilder Time-out Info

検証

チェックポイント

  1. 制限時間がスクリプトで設定されているウェブページで、制限時間が切れるまで待つ。

  2. 制限時間を延長する選択肢が提供されている。

判定基準

  • 2.を満たしていて、かつインタラクションを完了するために更なる時間が提供されている。

この達成方法が「十分な達成方法」の一つである場合、このチェックポイントや判定基準を満たしていなければ、それはこの達成方法が正しく用いられていないことを意味するが、必ずしも達成基準を満たしていないことにはならない。場合によっては、別の達成方法によってその達成基準が満たされていることもありうる。


SCR2: キーボード及びマウスのイベント・ハンドラを両方とも使用する

適用(対象)

スクリプトをサポートしているHTML及びXHTML

これは、次の達成基準に関連する達成方法である:

解説

この達成方法の目的は、マウスやフォーカスのイベントによって装飾画像が変化する、機器に依存しないイベントの使い方を説明することである。onmouseoverやonmouseoutイベントを使って、マウスがページ中のある要素に重なるか、又は離れたときに装飾画像が変化するようにする。また、onfocusonblurイベントを使って、要素がフォーカスされたか、フォーカスを失ったかによって画像を変更する。

下記の例では、アンカー要素の前に装飾画像がある。利用者がアンカータグにマウスオーバーすると、アンカータグの前の装飾画像が変化する。また、マウスがアンカーを離れると、画像は元に戻る。同じ画像の変化は、利用者がキーボードを使ってアンカー要素にフォーカスしたときにも起こる。フォーカスされたときに画像が変化し、フォーカスを失ったときには元の画像に戻る。これは、アンカー要素にonmouseoveronmouseoutonfocus及びonblurイベント・ハンドラを付加することで実現できる。このイベント・ハンドラはJavaScriptの関数でupdateImage()と呼ばれており、画像のsrc属性を変更する。updateImage()はonmouseover、onmouseout、onfocus、及びonblurイベントの応答として呼ばれる。

それぞれの画像には固有のIDが与えられている。このIDはどちらの画像が使われるかを表す論理値とともに、updateImage()に渡される:updateImage(imgId, isOver);。論理値trueは、マウスがアンカー要素に乗った場合、又はそれがフォーカスされた場合に渡される。falseは、マウスがアンカー要素から離れた場合、又はそれがフォーカスを失った場合に渡される。 updateImage()関数は、画像のIDを使用して画像を読み込み、その後に論理値の状態に応じてsrc属性を変更する。画像は装飾目的で使用されているので、alt属性値は空であることに注意する。

注記: サイズの近い画像を使用し、画像要素では幅と高さの属性値を指定することが望ましい。これは、画像が更新されることによりページのレイアウトが変化してしまうことを防ぐ。例では、同一サイズの画像が使用されている。

事例

事例 1

コード例:


<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"  "http://www.w3.org/TR/html4/loose.dtd">
 <html lang="ja">
 <head>
 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
 <title>デバイス非依存な手法で画像を変化させる</title>
 <script type="text/javascript">
 /* このfunctionは、img要素のsrc属性値を変更する。
  * param imgId - 変更する画像オブジェクトのID
  * param isOver - true:マウスオーバーしたとき、又はオブジェクトがフォーカスを受け取ったとき
  *                false:マウスオーバーを外したとき、又はフォーカスを外したとき
 */
 function updateImage(imgId, isOver) {
   var theImage = document.getElementById(imgId);
   if (theImage != null) { //could use a try/catch block for user agents supporting at least JavaScript 1.4
                           // These browsers support try/catch - NetScape 6, IE 5, Mozilla, Firefox
      if (isOver) {
        theImage.setAttribute("src","yellowplus.gif");
      }
      else {
        theImage.setAttribute("src","greyplus.gif");
      }
   }
 }
 </script>
 </head>
 <body>
 <p>次のリンクにマウスオーバーするか、タブ移動でフォーカスを移動させ、
 画像が変化するか確認してください。</p>
 <a href="http://www.w3.org/wai" onmouseover="updateImage('wai', true);" onfocus="updateImage('wai', true);"
   onmouseout="updateImage('wai',false);" onblur="updateImage('wai',false);">
 <img src="greyplus.gif" border="0" alt="" id="wai">
   W3C Web Accessibility Initiative</a> &amp;
 <a href="http://www.w3.org/International/" onmouseover="updateImage('i18n', true);" 
   onfocus="updateImage('i18n',true);" onmouseout="updateImage('i18n',false);"
   onblur="updateImage('i18n',false);">
   <img src="greyplus.gif" border="0" alt="" id="i18n">
   W3C Internationalization</a>
 </body>
 </html>

検証

チェックポイント

ウェブページを読み込み、マウス及びキーボードを用いてイベントを検証する。

  1. ウェブページが読み込まれたとき、“通常の”画像が期待通りに表示されている。

  2. マウスを使用

    1. イベント・ハンドラを含む要素の上にマウスを移動する(この事例ではアンカー要素)。元の画像が期待されている画像に変化する。

    2. マウスを要素から外す。画像が“通常の”画像に戻る。

  3. キーボードを使用

    1. キーボードを使ってイベント・ハンドラを含む要素にフォーカスを設定する。元の画像が期待されている画像に変化する。

    2. キーボードを使って要素からフォーカスを外す(一般的には別の要素にフォーカスを移す)。イメージが元の“通常の画像”に戻る。

  4. 画像の変更によって、ページ上の他の要素のレイアウトに影響がないかを確認する。

判定基準

  • 上記の全てを満たしている。

この達成方法が「十分な達成方法」の一つである場合、このチェックポイントや判定基準を満たしていなければ、それはこの達成方法が正しく用いられていないことを意味するが、必ずしも達成基準を満たしていないことにはならない。場合によっては、別の達成方法によってその達成基準が満たされていることもありうる。


SCR14: 不可欠ではないアラートの表示を任意にするために、スクリプトを使用する

適用(対象)

緊急ではない情報提供のアラートにスクリプトを使用するウェブコンテンツ技術

これは、次の達成基準に関連する達成方法である:

解説

この達成方法の目的は、メッセージ (アラート) を含むダイアログを利用者に表示することである。アラートが表示されたとき、それがフォーカスされると、利用者はそれを閉じるためにダイアログのOKボタンを押さなければならない。これらのアラートにフォーカスが移ってしまうと、特に、緊急ではない情報に使用されたとき、利用者の気が散ってしまうかもしれない。今日の名言、役に立つ小技、又は特定のイベントまでのカウントダウンなど、緊急ではない目的のアラートは、利用者がウェブページに提供された選択肢でそれらを有効にすることなしには現れないようにする。

この達成方法では、アラートを表示するかどうかの利用者の選択を保存するJavaScriptのグローバル変数に割り当てる。初期値は false にする。 ラッパー関数は、アラートを表示する前にこの変数の値をチェックするために作成される。alert() 関数を直接呼び出すよりもむしろ、アラートを表示するすべての呼び出しをこのラッパー関数にかけるようにする。ページの上部には、ページでのアラートの表示を利用者が有効にするためのボタンを提供する。この達成方法は訪問ベースで1回の訪問ごとに作動する。ページが読みこまれるたび、アラートは無効にされ、利用者は手動でそれらを有効にしなければならない。あるいは、コンテンツ制作者は、利用者の選択をセッションを越えて保存するためにクッキーを使用することができる。

事例

事例 1

以下のスクリプトは、利用者が「アラートを利用する」というボタンを選択するなら、10 秒ごとにアラートボックスに名言を表示する。利用者は再び「アラートを利用しない」を選択することで、名言のアラートボックスを非表示にすることができる。

コード例:


<script type="text/javascript">
var bDoAlerts = false;  // アラートを表示するかどうか指定するグローバル変数
/* アラートを有効/無効にする関数。
 * param ブーリアン型 bOn - trueでアラートを有効、falseで無効。
*/
function modifyAlerts(isEnabled) {
   bDoAlerts = isEnabled;
}
/* アラート表示のラッパー関数。bDoAlertsの値をチェックし
* bDoAlertsがtrueのときに alert() 関数を呼び出すだけ。
*/
function doAlert(aMessage) {
    if (bDoAlerts) {
       alert(aMessage);
    }
}
// 例 - 名言を表示するループ。
var gCounter = -1;  // カウンタを保存するグローバル変数
// quotes変数は名言のリストで初期化される
var quotes = new Array("quote 1", "quote 2", "quote 3", "quote 4", "quote 5");
function showQuotes() {
   if (++gCounter &amp;gt;= quotes.length) {★「&amp;gt;」は「>」ではないでしょうか?★
     gCounter = 0;
   }
   doAlert(quotes[gCounter]);
   setTimeout("showQuotes();", 10000);
}
showQuotes();
</script>

ページの本文内には、アラートを有効にしたり無効する方法を含める。以下はひとつの例である:

コード例:


<body>
<p>アラートボックスを使用した名言の表示を有効にするには、以下のボタンを押してください。<br />
<button id="enableBtn" type="button" onclick="modifyAlerts(true);">
アラートを利用する</button><br />
<button id="disableBtn" type="button" onclick="modifyAlerts(false);">
アラートを利用しない</button></p>

このコードを実装したサンプル: アラートの実装例

検証

チェックポイント

JavaScript を使用した緊急ではないアラートをサポートするウェブページにおいて:

  1. ウェブページを読み込んだ際、緊急ではないアラートが表示されない。

  2. 緊急ではないアラートを有効にするメカニズムがある。

  3. 緊急ではないアラートを有効にすると、アラートが表示される。

判定基準

  • 上記の全てを満たしている。

この達成方法が「十分な達成方法」の一つである場合、このチェックポイントや判定基準を満たしていなければ、それはこの達成方法が正しく用いられていないことを意味するが、必ずしも達成基準を満たしていないことにはならない。場合によっては、別の達成方法によってその達成基準が満たされていることもありうる。


SCR16: 制限時間が切れようとしていることを利用者に警告するスクリプトを提供する

適用(対象)

スクリプトによって制御された制限時間

これは、次の達成基準に関連する達成方法である:

解説

この達成方法の目的は、インタラクションを完了させるための時間がほとんど無いことを利用者に通知することである。スクリプトによって、時間制限のある機能が提供される場合には、そのスクリプトは利用者に制限時間が迫っていることを警告する機能を含み、より多くの時間を要求するためのメカニズムを提供することができる。制限時間の20秒以上前に、そのスクリプトは制限時間が迫っている事を伝え、利用者がさらに時間を必要とするかどうかを尋ねる確認ダイアログを提供する。もし利用者の答えが「はい」の場合、制限時間をリセットする。もし利用者の答えが「いいえ」又は返答がない場合、制限時間の終了を許可する。

この達成方法は、window.setTimeout()メソッドで設定された制限時間に関係する。例えば、60秒で制限時間が切れる設定の場合、制限時間を40秒に設定して、確認ダイアログを表示させることができる。確認ダイアログが表示された時、新しく時間制限が残り20秒に設定される。「制限時間の猶予期間」の満了時に、当初の設計では60秒の制限時間の満了の時にとられていたであろう処置がとられる。

事例

事例 1

ある株式市場相場ページは最新の統計を利用可能な状態を確保するため5分毎にページを更新するスクリプトを使用している。その5分間が終了する20秒前に、確認ダイアログが表示され、利用者がページを更新する前にもっと時間が必要かどうかを尋ねる。これにより、利用者に更新が差し迫っていることを認識させるとともに、もし希望するならそれを回避できるようにする。

コード例:


<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"<url>http://www.w3.org/TR/html4/loose.dtd">http://www.w3.org/TR/html4/loose.dtd</title>">
<html lang="ja">
<head>

<title>株式相場市況</title>
<script type="text/javascript">
<!--
function timeControl() {
	// タイマーを4分40秒に設定し、利用者に確認を求める
	setTimeout('userCheck()', 280000);
}
function userCheck() {
	// ページの再読み込みを20秒に設定する
	var id=setTimeout('pageReload()', 20000);
	// 利用者が「OK」を選択した場合、タイマーがリセットされる
	// それ以外の場合、サーバーによりページが再読み込みされる
	if (confirm("このページは20秒後に再読み込みされるように設定されています。
	それ以上の時間が必要ですか?"))
	{
	clearTimeout(id);
	timeControl();
	}
}
function pageReload() {
	window.location.reload(true);
}
timeControl();
-->
</script>
</head>
<body>
<h1>株式相場市況</h1>

...その他のコンテンツ...
</body>
</html>

検証

チェックポイント

スクリプトによって時間制限を制御しているウェブページにおいて:

  1. ページを読み込み、制限時間より20秒少ないタイマーを開始する。

  2. タイマーが切れるとき、差し迫った時間制限を警告する確認ダイアログが表示されることを確認する。

判定基準

  • 2.を満たしている。

この達成方法が「十分な達成方法」の一つである場合、このチェックポイントや判定基準を満たしていなければ、それはこの達成方法が正しく用いられていないことを意味するが、必ずしも達成基準を満たしていないことにはならない。場合によっては、別の達成方法によってその達成基準が満たされていることもありうる。


SCR18: クライアントサイドのバリデーション及びアラートを提供する

適用(対象)

利用者の入力を検証するコンテンツ

これは、次の達成基準に関連する達成方法である:

解説

この達成方法の目的は、クライアントサイドのスクリプトによって、各フィールドで利用者が入力する値を確認することである。エラーが見つかった場合、警告ダイアログを表示し、エラーの内容をテキストで示す。警告ダイアログを閉じるとともに、スクリプトによってキーボードフォーカスをエラーが起こったフィールドに移動させれば、それは利用者にとって役立つ。

事例

事例 1: イベントハンドラで単一のコントロールをチェックする

以下のスクリプトは、有効な日付がフォームのコントロールに入力されたかをチェックする。

コード例:


<label for="date">日付:</label>
<input type="text" name="date" id="date" 
onchange="if(isNaN(Date.parse(this.value))) 
alert('alert('このコントロールは日付が正しくありません。値を再び入力してください。');" />

事例 2: 利用者がフォームを送信したときに複数のコントロールをチェックする

次の例はフォーム内の複数のコントロールを表している。form 要素は、利用者がフォームを送信しようとした際、検証スクリプトを実行するために、イベントハンドラを作成する onsubmit 属性を用いている。検証で問題がない場合、イベントは true を返し、フォームの送信を続行する。検証でエラーが検出された場合は、利用者が問題を修正できるようエラーメッセージを表示し、送信を取り消すために false を返す。

注記 1: この事例は簡潔さのためにアラートを用いて説明している。利用者により役立つ通知は、問題のあるコントロールをハイライトし、エラーの内容とデータの修正が必要なコントロールに移動する方法をページ上に示すことである。

注記 2: この事例では簡潔さのために form 要素に onsubmit 属性を用いているが、通常であればページがロードした際にフォーム送信用のイベントリスナーを作成する。

スクリプトコード:


function validate() {
	// initialize error message
	var msg = "";
	
	//validate name
	var pattern = /^[a-zA-Z\s]+$/;
	var el = document.getElementById("name");
	if (!pattern.test(el.value))  msg += "名前は文字及びスペースのみ含むことができます。";
	
	// validate number
	var pattern = /^[\d\-+\.\s]+$/;
	var el = document.getElementById("tel");
	if (!pattern.test(el.value))  msg += "電話番号は数字及びセパレーターのみ含むことができます。";
	
	if (msg != "") {
		alert(msg);
		return false;
	} else return true;
}

フォームコード:


<form action="multiple-controls.html" onsubmit="return validate()">
	<p>
		<label for="name">名前: </label>
		<input type="text" name="name" id="name" />
	</p>
	<p>
		<label for="tel">電話番号: </label>
		<input type="text" name="tel" id="tel" />				
	</p>
	<p>
		<input type="submit" />
	</p>
</form>

利用者がフォームを送信したときに複数のコントロールをチェックする実装例にこの実装方法のデモがある。

検証

チェックポイント

特定の入力を必要とするフォームのフィールドに対して:

  1. 無効なデータを入力する。

  2. エラーを説明している警告が提供されている。

判定基準

  • 2. を満たしている

この達成方法が「十分な達成方法」の一つである場合、このチェックポイントや判定基準を満たしていなければ、それはこの達成方法が正しく用いられていないことを意味するが、必ずしも達成基準を満たしていないことにはならない。場合によっては、別の達成方法によってその達成基準が満たされていることもありうる。


SCR19: 状況の変化を引き起こすことのないように、select 要素の onchange イベントを使用する

適用(対象)

スクリプトをサポートするHTML及びXHTML。この達成方法では、JavaScript 1.4 の try/catch 構文を用いる。

これは、次の達成基準に関連する達成方法である:

ユーザエージェント及び支援技術によるサポート

SCR19 に関するユーザエージェントサポートノート (英語)を参照のこと。

解説

この達成方法の目的は、ウェブページの他の要素を更新するselect要素においてonchangeイベントを正しく使用する方法を示すことである。この達成方法は、状況の変化を引き起こさない。ウェブページに一つかそれ以上のselect要素があるとき、一方のonchangeイベントは、そのウェブページの別のselect要素における選択肢を更新できる。そして、select要素によって必要とされるデータのすべてが、ウェブページの中に含まれている。

ウェブページでの音声読み上げ順序において、選択によって変更されるアイテムが、トリガーとなるselect要素の後にあることに注意することが重要である。これは、支援技術が変化を察知するのを確実にし、変更されたアイテムがフォーカスされたとき、利用者は新しいデータを認識する。なお、この達成方法は、ユーザエージェントによるJavaScriptのサポート状況に依存する。

事例

事例 1

この事例には、2つのselect要素がある。最初のselect要素でアイテムが選択されたとき、二つめのselect要素の選択肢が適切に更新される。最初のselect要素には、大陸のリストがある。そして、二つめのselect要素には、選択された大陸に位置する国々の一部のリストがある。onchangeイベントは、大陸の選択に連動している。大陸の選択が変わると、国の選択肢は、ドキュメント・オブジェクト・モデル(DOM)を通してJavaScriptを用いて変更される。必要であるすべてのデータ、国と大陸のリスト、はウェブページの中に含まれている。

以下のコードの概要:

  • トリガーとなるselect要素の大陸ごとの国々のリストを含むcountryLists配列

  • 大陸のselect要素のonchangeイベントによって呼ばれるcountryChange() 関数

  • ウェブページの本文のselect要素を作成するXHTMLコード

コード例:


<?xml version="1.0" encoding="UTF-8"?> 
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> 
  <head> 
    <meta http-equiv="content-type" content="text/xhtml; charset=utf-8" /> 
    <title>動的なセレクトメニュー</title> 

<script type="text/javascript">
 //<![CDATA[ 
 // 国の選択項目のリストに現れるのと同じ順の選択可能な国の配列 
 var countryLists = new Array(4) 
 countryLists["empty"] = ["国を選択してください"]; 
 countryLists["North America"] = ["カナダ", "アメリカ合衆国", "メキシコ"]; 
 countryLists["South America"] = ["ブラジル", "アルゼンチン", "チリ", "エクアドル"]; 
 countryLists["Asia"] = ["ロシア", "中国", "日本"]; 
 countryLists["Europe"]= ["イギリス", "フランス", "スペイン", "ドイツ"]; 
 /* CountryChange() はselect要素のonchangeイベントから呼び出される。 
 * param selectObj - onchangeイベントで生成されるselectオブジェクト。
 */ 
 function countryChange(selectObj) { 
 // 選択された選択肢のインデックスを得る 
 var idx = selectObj.selectedIndex; 
 // 選択された選択肢の値を得る 
 var which = selectObj.options[idx].value; 
 // countryLists 配列から項目のリストを検索するために選択された選択肢の値を使う 
 cList = countryLists[which]; 
 // そのIDを通して国のselect要素を得る
 var cSelect = document.getElementById("country"); 
 // 国のリストから現在の選択肢を削除する 
 var len=cSelect.options.length; 
 while (cSelect.options.length > 0) { 
 cSelect.remove(0); 
 } 
 var newOption; 
 // 新しい選択肢を生成する 
 for (var i=0; i<cList.length; i++) { 
 newOption = document.createElement("option"); 
 newOption.value = cList[i];  // 選択肢の文字列と値は同じとする 
 newOption.text=cList[i]; 
 // 新しい選択肢を追加する 
 try { 
 cSelect.add(newOption);  // これはDOMをサポートするブラウザでは失敗するが、IEには必要 
 } 
 catch (e) { 
 cSelect.appendChild(newOption); 
 } 
 } 
 } 
//]]>
</script>
</head>
<body>
  <noscript>このページはJavaScriptが有効で、関数が正しく動作可能である必要があります。</noscript>

  <h1>動的なセレクトメニュー</h1>
  <label for="continent">大陸を選択</label>
  <select id="continent" onchange="countryChange(this);">
    <option value="empty">大陸を選択してください</option>

    <option value="North America">北米</option>
    <option value="South America">南米</option>
    <option value="Asia">アジア</option>
    <option value="Europe">ヨーロッパ</option>

  </select>
  <br/>
  <label for="country">国を選択</label>
  <select id="country">
    <option value="0">国を選択してください</option>

  </select>
</body>
 </html>

このコードの実装サンプル:動的なセレクトメニュー

参考リソース

この参考リソースは、あくまでも情報提供のみが目的であり、推薦などを意味するものではない。

(今のところ、なし。)

検証

チェックポイント

  1. トリガーとなるselect要素(この事例では、大陸を選択するセレクトメニュー)で、選択肢の値を変える。

  2. トリガーによって更新されたselect要素(この事例では、国を選択するセレクトメニュー)へ移動する。

  3. 適切な選択肢の値が、2. のselect要素に表示されている。

  4. 選択肢の値を変えることなく、1. のトリガーとなるselect要素へ移動する。

  5. 適切な選択肢の値が、関連付けられた要素(2. のselect要素)にまだ表示されている。

関連付けられた要素(2. のselect要素)の変化が認識されることを確かめるために、select要素を支援技術を用いて検証することが望ましい。

判定基準

  • 3. 及び 5. を満たしている。

この達成方法が「十分な達成方法」の一つである場合、このチェックポイントや判定基準を満たしていなければ、それはこの達成方法が正しく用いられていないことを意味するが、必ずしも達成基準を満たしていないことにはならない。場合によっては、別の達成方法によってその達成基準が満たされていることもありうる。


SCR20: キーボードとその他のデバイス特有の機能を両方とも使用する

適用(対象)

機能を実装するためにスクリプトを用いる全てのコンテンツ

これは、次の達成基準に関連する達成方法である:

解説

この達成方法の目的は、イベントと関連付けられたスクリプト機能を含むコードを伴った、キーボード固有及びマウス固有のイベント双方の使用を明示することである。キーボード固有及びマウス固有のイベントを一緒に用いることにより、さまざまな種類の機器でコンテンツを操作できることを保証することができる。例えば、スクリプトがkeypressを認識したときに、マウスボタンをクリックしたときと同じ動作を行うことができるようにする。このテクニックにより、キーボードによるアクセスだけでなく他の機器によるアクセスの達成基準を満たすことができる。

JavaScriptでよく使用されるイベント・ハンドラには、onblur、onchange、onclick、ondblclick、onfocus、onkeydown、onkeypress、onkeyup、onload、onmousedown、onmousemove、onmouseout、onmouseover、onmouseup、onreset、onselect、onsubmit、onunloadが含まれる。いくつかのマウス固有の機能には、論理的に対応するキーボード固有の機能がある(例えば'onmouseover'と'onfocus'のように)。キーボード向けのイベント・ハンドラは、対応するマウス向けの機能とともに提供すべきである。

次の表は、マウスイベント・ハンドラに対応するキーボードイベント・ハンドラの候補である。

対応表
マウス向けキーボード向け
mousedown keydown
mouseup keyup
click [1] keypress [2]
mouseover focus
mouseout blur

1 clickは基本的にはマウスのイベント・ハンドラであるが、ほとんどの HTML 及び XHTML 向けのユーザエージェントは、HTML のネイティブコントロール(例: ボタン又はリンク)が有効化された場合、マウス又はキーボードのどちらで有効化されたかにかかわらず、イベントを処理することができる。そのため、もともとフォーカスできる HTML 要素にハンドラを追加するときは、実際にはキーボード用のイベントを補完する必要はない。しかし、下記の事例 2 のように他のイベントにハンドラを追加するときは、必要である。

2 keypress イベント・ハンドラは、どのキーに対しても有効であることから、そのイベント・ハンドラ関数では、イベントを処理する前に、Enterキーが押されたかどうかをチェックすべきである。そうでなければ、イベント・ハンドラは利用者が任意のキーを押すたびに実行され、コントロールから抜けるために Tab キーを押すような場合にも実行されるので、通常は望ましくない。

dblclick 及び mousemove のような)いくつかのマウス固有の機能には、対応するキーボード固有の機能がない。つまり、いくつかの機能は機器別に違った実装をしなければならないということである(例えば、実装されているマウス固有の機能と同等の機能を、キーボードから実行するための一連のボタン操作を含むようにする)。

事例

事例 1

この画像リンクの例では、利用者がポインタを画像に重ねると画像が変化する。キーボード利用者に同様の体験を提供するには、利用者が画像リンクにTabキーで移動した場合に、画像を変化させればよい。

コード例:


&lt;a href="menu.php" onmouseover="swapImageOn('menu')" onfocus="swapImageOn('menu')" 
onmouseout="swapImageOff('menu')" onblur="swapImageOff('menu')"&gt; 
&lt;img id="menu" src="menu_off.gif" alt="メニュー" /&gt; 
&lt;/a&gt;

事例 2

この事例では、マウスとキーボードの両方を用いて機能を実行できる画像のカスタム・コントロールを紹介している。マウスイベントの onclick は、対応するキーボードイベントの onkeypress によって補完されている。tabindex 属性は、キーボードを用いてTabキーで移動した際に、画像の上で停止させるためのものである。この事例では nextPage() 関数が、キーボードのキー押下が Enter キーであるかどうかをチェックしていることに注目してほしい。もしチェックしなければ、画像にフォーカスがあるときには、どのキーが押下されても常に反応してしまうため望ましくない。

コード例:


&lt;img onclick="nextPage();" onkeypress="nextPage();" tabindex="0" src="arrow.gif" 
alt="次のページへ移動"&gt;

注記: この例では img 要素に tabindex を用いている。現時点では(文法的に)妥当ではないが、この機能を実装するための古典的なテクニックとして用いられている。このようなカスタム・コントロールでは、コントロールの役割(role)と状態(state)を支援技術に引き渡すために WAI-ARIA も用いるべきである。

参考リソース

この参考リソースは、あくまでも情報提供のみが目的であり、推薦などを意味するものではない。

検証

チェックポイント

  1. 全てのインタラクティブな機能を探す。

  2. それらのインタラクティブな機能全てに、キーボードだけを使ってアクセスできる。

判定基準

  • 2. を満たしている。

この達成方法が「十分な達成方法」の一つである場合、このチェックポイントや判定基準を満たしていなければ、それはこの達成方法が正しく用いられていないことを意味するが、必ずしも達成基準を満たしていないことにはならない。場合によっては、別の達成方法によってその達成基準が満たされていることもありうる。


SCR21: ページにコンテンツを追加するために、DOM(ドキュメント・オブジェクト・モデル)を使用する

適用(対象)

HTML及びXHTMLの中で利用されるECMAScript

これは、次の達成基準に関連する達成方法である:

ユーザエージェント及び支援技術によるサポート

SCR21 に関するユーザエージェントサポートノート (英語)を参照のこと。

解説

この達成方法の目的は、document.write又はobject.innerHTMLの代わりにDocument Object Model (DOM)の機能を用いて、ページ中にコンテンツを追加することである。document.write()メソッドはXHTMLで正しいMIMEタイプ(application/xhtml+xml)が指定されているときに動作せず、innerHTMLプロパティはDOMの仕様ではないため利用すべきでない。もしDOMの機能を利用してコンテンツを追加すれば、ユーザエージェントはDOMにアクセスしてコンテンツを取り込むことができる。createElement()関数を使ってDOMの中に要素を作成することもできる。createTextNode()は要素に関連付けられたテキストを作成するのに用いられる。appendChild()removeChild()insertBefore()及びreplaceChild()関数は、要素やノードを追加したり削除したりするのに用いられる。その他のDOM関数は、作成された要素に属性を与えるときに使用される。

注記: フォーカス可能な要素を文書に追加するとき、tabindex属性を用いて明示的なタブ順序を指定してはならない。なぜなら、文書の中央にフォーカス可能な要素を追加するときに問題が発生するからである。tabindex属性を明示的に設定しないことで、デフォルトのタブ順序が新しい要素に割り当てられるようにする。

事例

事例 1

この例では、クライアントサイドスクリプトの使用法として、フォームの検証方法を紹介している。もしエラーがみつかれば、適切なエラーメッセージが表示される。この例ではDOM関数を使用し、タイトル、エラーに関する短い説明、及びエラー一覧の順序付リストを含むエラー通知を追加している。タイトルの内容はリンクとして書かれているので、focusメソッドを使って利用者の注意をエラーに向けることができる。個別のリスト項目もまた、リンクとして書かれているので、そのリンク先に移動したときにエラーのあるフォームのフィールドにフォーカスできるように書かれている。

この例では、簡単にするために二つのテキストフィールドだけを検証しているが、一般的なフォームハンドラにするために容易に拡張することができる。クライアントサイドの検証は、それを唯一の検証とすべきではなく、サーバーサイドの検証でも確認するべきである。クライアントサイドでの検証の利点は、利用者にすぐにフィードバックを提供することで、サーバーからエラーが帰ってくるまでの間、彼らを待たせることがないこと、及びサーバーへの余計なトラフィックを軽減できることである。

次の例はフォームにイベント・ハンドラを追加するスクリプトである。もしスクリプトが有効であれば、サーバーにフォームが送信される前にvalidateNumbers()関数がクライアントサイドの検証のために呼び出される。もしスクリプトが有効でなければ、フォームはすぐにサーバー側に送信されるので、検証機能はサーバーにも実装されるべきである。

コード例:


window.onload = initialise;
function initialise()
{
  // 標準に準拠したユーザエージェントが対象
  if (!document.getElementById || !document.createElement || !document.createTextNode)
    return;

  // フォームにイベントハンドラを付加
  var objForm = document.getElementById('numberform');
  objForm.onsubmit= function(){return validateNumbers(this);};
} 

次の例はvalidationの機能である。エラーメッセージの要素を作成するためにcreateElement()、createTextNode()、及びappendChild() DOM関数を使用しているところに注目して欲しい。

コード例:


function validateNumbers(objForm)
{
  // フィールドを検証
  var bFirst = isNumber(document.getElementById('num1').value);
  var bSecond = isNumber(document.getElementById('num2').value);
  // 問題がある場合、エラーを表示
  if (!bFirst || !bSecond)
  {
    var objExisting = document.getElementById('validationerrors');
    var objNew = document.createElement('div');
    var objTitle = document.createElement('h2');
    var objParagraph = document.createElement('p');
    var objList = document.createElement('ol');
    var objAnchor = document.createElement('a');
    var strID = 'firsterror';
    var strError;
    // 見出し要素にリンクを含めることによって、スクリーンリーダーは
    // フォーカスを置くことができる - そのリンク先はエラー一覧の中で 
    // 一番最初のエラー項目とする
    objAnchor.appendChild(document.createTextNode('Errors in Submission'));
    objAnchor.setAttribute('href', '#firsterror');
    objTitle.appendChild(objAnchor);
    objParagraph.appendChild(document.createTextNode('Please review the following'));
    objNew.setAttribute('id', 'validationerrors');
    objNew.appendChild(objTitle);
    objNew.appendChild(objParagraph);
    // 発見したエラーすべてをエラー一覧に追加
    if (!bFirst)
    {
      strError = '最初の数字には、数値を入力してください。';
      objList.appendChild(addError(strError, '#num1', objForm, strID));
      strID = '';
    }
    if (!bSecond)
    {
      strError = '2番目の数字には、数値を入力してください。';
      objList.appendChild(addError(strError, '#num2', objForm, strID));
      strID = '';
    }
    // エラー情報に一覧を追加
    objNew.appendChild(objList);
    // 既存のエラーがあった場合、新規のエラーと置き換える
    // あるいは、新規のエラーをフォームの先頭に追加する
    if (objExisting)
      objExisting.parentNode.replaceChild(objNew, objExisting);
    else
    {
      var objPosition = objForm.firstChild;
      objForm.insertBefore(objNew, objPosition);
    }
    // フォーカスを見出しにあるアンカーに置いて、スクリーンリーダーに
    // 対してエラーがあることを警告する
    objAnchor.focus();
    // フォームを送信しない
    objForm.submitAllowed = false;
    return false;
  }
  return true;
}

// 数字を検証する関数
function isNumber(strValue)
{
  return (!isNaN(strValue) &amp;&amp; strValue.replace(/^\s+|\s+$/, '') !== '');
} 

以下は、エラーメッセージを作成して、関連するフォームのフィールドにフォーカスさせるための補助関数である。

コード例:


// エラー内容を説明する、エラーのフォームフィールドへのリンクの
// リスト項目を作成する関数
function addError(strError, strFragment, objForm, strID)
{
  var objAnchor = document.createElement('a');
  var objListItem = document.createElement('li');
  objAnchor.appendChild(document.createTextNode(strError));
  objAnchor.setAttribute('href', strFragment);
  objAnchor.onclick = function(event){return focusFormField(this, event, objForm);};
  objAnchor.onkeypress = function(event){return focusFormField(this, event, objForm);};
  // strIDに値がある場合、これがリストで一番目のエラーとなる
  if (strID.length > 0)
    objAnchor.setAttribute('id', strID);
  objListItem.appendChild(objAnchor);
  return objListItem;
}

// エラーのフォームフィールドにフォーカスを置く関数
function focusFormField(objAnchor, objEvent, objForm)
{
  // キーボードナビゲーションを可能にするAllow keyboard navigation over links
  if (objEvent &amp;&amp; objEvent.type == 'keypress')
    if (objEvent.keyCode != 13 &amp;&amp; objEvent.keyCode != 32)
      return true;
  // フォーカスをフォーム・コントロールに設定する
  var strFormField = objAnchor.href.match(/[^#]\w*$/);
  objForm[strFormField].focus();
  return false;
} 

以下は事例のフォーム用HTMLである。

コード例:


<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html lang="ja">
<head>
	<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
	<title>ECMAScript フォームの検証</title>
	<script type="text/javascript" src="validate.js"></script>
</head>
<body>
<h1>フォームの検証</h1>
<form id="numberform" method="post" action="form.php">

<fieldset>
<legend>数字のフィールド</legend>
<p>
<label for="num1">最初の数字を入力</label>
<input type="text" size="20" name="num1" id="num1">
</p>
<p>

<label for="num2">2番目の数字を入力</label>
<input type="text" size="20" name="num2" id="num2">
</p>
</fieldset>
<p>
<input type="submit" name="submit" value="フォームを送信">
</p>
</form>

</body>
</html> 

この例はクライアントサイドスクリプトに限定しているため、サーバーサイドの検証によって補完されるべきである。例では、クライアントサイドスクリプトが利用できるときのエラーメッセージの作成に限定される。

このコードの実装サンプル:フォームの検証

参考リソース

この参考リソースは、あくまでも情報提供のみが目的であり、推薦などを意味するものではない。

(今のところ、なし。)

検証

チェックポイント

動的に新しいコンテンツを作成するページに対して:

  1. (ソースコードを検証して、)新しいコンテンツがdocument.write()、innerHTML,、outerHTML、innerText又はouterTextを用いて作成されていない。

判定基準

  • 1.を満たしている。

この達成方法が「十分な達成方法」の一つである場合、このチェックポイントや判定基準を満たしていなければ、それはこの達成方法が正しく用いられていないことを意味するが、必ずしも達成基準を満たしていないことにはならない。場合によっては、別の達成方法によってその達成基準が満たされていることもありうる。


SCR22: 点滅を制御し、5 秒以内に停止させるために、スクリプトを使用する

適用(対象)

スクリプトで制御されたコンテンツの点滅をサポートするウェブコンテンツ技術

これは、次の達成基準に関連する達成方法である:

解説

この達成方法の目的は、スクリプトによる点滅を、5秒未満で停止する設定にできるよう制御することである。 スクリプトを用いて、コンテンツの点滅効果を開始し、表示と非表示の状態切り替えを制御し、そして5秒以下で停止させる。setTimeout()関数を用いて、点滅するコンテンツの表示と非表示の状態を切り替え、点滅の回数と所要時間の積が5秒近くになった時に停止させる。

事例

事例 1

この例では、JavaScriptを用いてHTML及びXHTMLコンテンツの点滅を制御する。JavaScriptは、コンテンツの表示状態を制御して点滅効果を生みだす。効果の開始を制御し、5秒以内に停止させる。

コード例:

...
<div id="blink1" class="highlight">新商品!</div>
<script type="text/javascript">
<!--
// 点滅「on」状態
function show()
{
	if (document.getElementById)
	document.getElementById("blink1").style.visibility = "visible";
}
// 点滅「off」状態
function hide()
{
	if (document.getElementById)
	document.getElementById("blink1").style.visibility = "hidden";
}
// 点滅効果を出すために「on」と「off」の状態を450ミリ秒ごとに切り替え
// 4500ミリ秒後に終了(5秒未満)
for(var i=900; i < 4500; i=i+900)
{
	setTimeout("hide()",i);
	setTimeout("show()",i+450);
}
-->
</script>
...

検証

チェックポイント

点滅しているコンテンツのそれぞれのインスタンスに対して:

  1. 点滅効果が開始される時、5秒間のタイマーを開始させる。

  2. タイマーが切れるとき、点滅が停止している。

判定基準

  • 点滅しているコンテンツのそれぞれのインスタンスが2.を満たしている。

この達成方法が「十分な達成方法」の一つである場合、このチェックポイントや判定基準を満たしていなければ、それはこの達成方法が正しく用いられていないことを意味するが、必ずしも達成基準を満たしていないことにはならない。場合によっては、別の達成方法によってその達成基準が満たされていることもありうる。


SCR24: 利用者の要求に応じて新しいウィンドウを開くために、プログレッシブ・エンハンスメントを使用する

適用(対象)

HTML 4.01 及び XHTML 1.0

これは、次の達成基準に関連する達成方法である:

解説

この達成方法の目的は、利用者が要求していない新しいウィンドウの出現によって引き起こされうる混乱を回避することである。突然新しいウィンドウが開くと、利用者は混乱したり、そのことに気づかなかったりする。文書型がtarget属性を認めていない場合(HTML 4.01 Strict や XHTML 1.0 Strict には存在しない)、又はコンテンツ制作者がtarget属性の使用を好まない場合には、ECMAScriptを用いて新しいウィンドウを開くことができる。以下にある事例は、スクリプトを用いて新しいウィンドウを開く方法を示している。その事例では、リンク(a要素)にイベントハンドラを追加して、利用者にリンク先のコンテンツが新しいウィンドウで開くことを事前に知らせている。

事例

事例 1

マークアップ:

スクリプトはドキュメントのhead要素内に組み込まれており、リンクにはスクリプトのフックとなるid属性がある。

コード例:


<script type="text/javascript" src="popup.js"></script>
…
<a href="help.html" id="newwin">ヘルプを表示</a>

スクリプト:

コード例:


// ブラウザによるイベント登録のサポートは不十分だが
// 従来のイベントモデルを用いる
window.onload = addHandlers;

function addHandlers()
{
  var objAnchor = document.getElementById('newwin');

  if (objAnchor)
  {
    objAnchor.firstChild.data = objAnchor.firstChild.data + ' (新しいウィンドウで開く)';
    objAnchor.onclick = function(event){return launchWindow(this, event);}
    // UAAG ではユーザエージェントにデバイス非依存な方法でイベントを処理することを
    // 要求しているが、そうしないブラウザが多いのでキーボードイベントを追加する
    objAnchor.onkeypress = function(event){return launchWindow(this, event);}
  }
}

function launchWindow(objAnchor, objEvent)
{
  var iKeyCode, bSuccess=false;

  // キーボードからのイベントである場合、利用者がリンクをリクエストしたときだけ
  // 新しいウィンドウを開くようにする(リターン又はスペース)
  if (objEvent &amp;&amp; objEvent.type == 'keypress')
  {
    if (objEvent.keyCode)
      iKeyCode = objEvent.keyCode;
    else if (objEvent.which)
      iKeyCode = objEvent.which;

    // キャリッジ・リターン又はスペースではない場合、ユーザエージェントが
    // アクションの処理を継続するようにtrueを返す
    if (iKeyCode != 13 &amp;&amp; iKeyCode != 32)
      return true;
  }

  bSuccess = window.open(objAnchor.href);

  // ウィンドウが開かなかった場合、ブラウザには同じウィンドウで開くという
  // デフォルトのアクションを継続させる
  if (!bSuccess)
    return true;

  // ウィンドウが開いたら、ブラウザによる処理をそこで止める
  return false;
} 

参考リソース

この参考リソースは、あくまでも情報提供のみが目的であり、推薦などを意味するものではない。

検証

チェックポイント

  1. ドキュメントにあるリンクを起動して、新しいウィンドウが開くかどうかをチェックする。

  2. 新しいウィンドウを開くリンクが、次の全てをスクリプトを用いて実装されている:

    1. リンクが新しいウィンドウを開くことを明示している

    2. デバイス非依存のイベントハンドラを用いている

    3. 新しいウィンドウを開けない場合には、ブラウザが同じウィンドウにリンク先のコンテンツを開くようにしている

判定基準

  • 2.を満たしている。

この達成方法が「十分な達成方法」の一つである場合、このチェックポイントや判定基準を満たしていなければ、それはこの達成方法が正しく用いられていないことを意味するが、必ずしも達成基準を満たしていないことにはならない。場合によっては、別の達成方法によってその達成基準が満たされていることもありうる。


SCR26: 動的なコンテンツを DOM のそのトリガーとなる要素の直後に挿入する

適用(対象)

HTML及びXHTML、スクリプト

これは、次の達成基準に関連する達成方法である:

解説

この達成方法の目的は、Document Object Model(DOM)に挿入されたユーザインタフェースの要素をタブ順序及びスクリーンリーダーの読み上げ順序がユーザエージェント標準のふるまいによって正しく設定されるような方法で配置することである。この達成方法は、メニューやダイアログのように隠れているものと表示されているもの、全てのユーザインタフェース要素に利用することができる。

スクリーンリーダーの読み上げ順序は、Document Object Model 内の HTML 又は XHTML の要素の順序に基づいており、それはタブ順序についても同様である。この達成方法では、新しいコンテンツを DOM のそのトリガーとなる要素の直後に挿入する。トリガーとなる要素は、リンク又はボタンでなければならず、スクリプトはその onclick イベントにより呼び出されなければならない。これらの要素はもともとフォーカス可能であり、その onclick イベントはデバイスに依存しない。フォーカスは選択された要素に残り、その後に挿入された新しいコンテンツは、タブ順序及びスクリーンリーダーの読み上げ順序の両方において、次の順番となる。

この達成方法は同期された更新にも利用できることに注目して欲しい。(AJAX と呼ばれることのある)非同期の更新では、支援技術に非同期のコンテンツが挿入されたことを通知するために追加の達成方法が必要となる。

事例

事例 1

この例では、リンクがクリックされた際にメニューを生成し、そのリンクの後に挿入する。リンクの onclick イベントは新しいメニューのための ID をパラメータとして渡す ShowHide スクリプトを呼び出すために使用される。

コード例:


<a href="#" onclick="ShowHide('foo',this)">切り替え</a>

ShowHide スクリプトは新しいメニューを含む div を生成し、リンクを挿入する。最終行がスクリプトの核心となる。スクリプトのトリガーとなる要素の親を探し、新しい子として生成された div をそれに追加する。これにより、新しい div は DOM 内でリンクの次になる。利用者がタブを押したときには、フォーカスがメニュー内で最初のフォーカス可能な項目となる生成されたリンクに移動する。

コード例:


ShowHide関数(id,src)
{
	var el = document.getElementById(id);
	if (!el)
	{
		el = document.createElement("div");
		el.id = id;
		var link = document.createElement("a");
		link.href = "javascript:void(0)";
		link.appendChild(document.createTextNode("Content"));
		el.appendChild(link);
		src.parentElement.appendChild(el);
	}
	else
	{
		el.style.display = ('none' == el.style.display ? 'block' : 'none');
	}
} 

CSS は div およびリンクをメニューのように見せるために利用される。

検証

チェックポイント

  1. ポップアップではないダイアログのトリガーとなる全てのエリアを探す。

  2. そのダイアログがボタン又はリンクのクリックイベントによりトリガーされる。

  3. スクリプトによって生成された DOM を調査できるツールを使って、ダイアログが DOM 内で次の位置にきている。

判定基準

  • 2. 及び 3. を満たしている。

この達成方法が「十分な達成方法」の一つである場合、このチェックポイントや判定基準を満たしていなければ、それはこの達成方法が正しく用いられていないことを意味するが、必ずしも達成基準を満たしていないことにはならない。場合によっては、別の達成方法によってその達成基準が満たされていることもありうる。


SCR27: DOM を用いて、ページ上にある複数のセクションを並び替える

適用(対象)

HTMLおよびXHTML、スクリプト

これは、次の達成基準に関連する達成方法である:

解説

この達成方法の目的は、コンポーネントを再配置するための極めてユーザブルかつアクセシブルなメカニズムを提供することである。再配置するためのメカニズムのうち、もっとも一般的なものは、コンポーネントに番号をつけることができる設定ページに利用者を送ること、又は、コンポーネントをドラッグアンドドロップして希望する位置へ移動できるようにすることのふたつである。ドラッグアンドドロップの方が、ひとつずつ項目を適当な位置に並べることができ、結果を感覚的に得られるため、はるかにユーザブルな方法である。残念なことに、ドラッグアンドドロップはマウスの利用に頼った方法である。この達成方法は、利用者がコンポーネントのメニューを使って、それらを機器に依存することなく適当な位置に再配置することを可能にする。ドラッグアンドドロップによる再配置機能の代替として、もしくはそれと併用して利用することができる。

メニューはリンクリストで、コンテンツを再配置するスクリプトのトリガーとなる、機器に依存しないonclickイベントを使用している。コンテンツは単に視覚的にだけでなく、Document Object Model (DOM)でも再配置されているので、すべての機器向けに正しい順序となっている。

事例

事例 1

この例は上下間の再配置を行う。このアプローチはまた、右と左のオプションを追加することで、2次元での再配置にも利用できる。

この例のコンポーネントは順序無しリストのリスト項目である。順序無しリストは、こうしたコンポーネントのような類似項目のためのとてもよいセマンティックモデルである。メニューを使う方法も、他のタイプのグループ化に使用できる。

モジュールはリスト項目であり、それぞれのモジュールは、div要素内のコンテンツに加えて、入れ子になったリストとして表されたメニューを含んでいる。

コード例:


    &lt;ul id="swapper"&gt;
    &lt;li id="black"&gt;
        &lt;div class="module"&gt;
            &lt;div class="module_header"&gt;
                &lt;!-- メニューへのリンク --&gt;
                &lt;a href="#" onclick="ToggleMenu(event);"&gt;menu&lt;/a&gt;
                &lt;!-- メニュー --&gt;
                &lt;ul class="menu"&gt;
                    &lt;li&gt;&lt;a href="#" onclick="OnMenuClick(event)" 
                        onkeypress="OnMenuKeypress(event);"&gt;up&lt;/a&gt;&lt;/li&gt;
                    &lt;li&gt;&lt;a href="#" onclick="OnMenuClick(event)" 
                        onkeypress="OnMenuKeypress(event);"&gt;down&lt;/a&gt;&lt;/li&gt;
                &lt;/ul&gt;
            &lt;/div&gt;
            &lt;div class="module_body"&gt;
                blackモジュールのテキスト
            &lt;/div&gt;
        &lt;/div&gt;
    &lt;/li&gt;
    ...
&lt;/ul&gt; 

ここまでは、簡単なツリーの例でメニューを出したり隠したりする方法をとりあげてきたので、モジュールを入れ替えるコードについても着目する。イベントを同期させてデフォルトのリンクアクションをキャンセルしてから、作業に移動する。最初に、これから作業する要素、メニュー、再配置されるモジュール、メニューリンクのための一連のローカル変数をセットする。それから、再配置の方向を確認した後に、入れ替えるノードの取得を試みる。ノードを見つけた場合、swapNode()を呼び出して二つのモジュールを入れ替え、 PositionElement()でモジュールと共に絶対配置されたメニューを移動し、すべてが完了したメニュー項目にフォーカスを設定する。

コード例:


MoveNode 関数(evt,dir)
{
    HarmonizeEvent(evt);
    evt.preventDefault();

    var src = evt.target;
    var menu = src.parentNode.parentNode;
    var module = menu.parentNode.parentNode.parentNode;
    var menuLink = module.getElementsByTagName("a")[0];
    var swap = null;
    
    switch(dir)
    {
        case 'up':
        {
            swap = module.previousSibling;
            while (swap &amp;&amp; swap.nodeType != 1)
            {
                swap = swap.previousSibling;
            }
            break;
        }
        case 'down':
        {
            swap = module.nextSibling;
            while (swap &amp;&amp; swap.nodeType != 1)
            {
                swap = swap.nextSibling;
            }
            break;
        }
    }
    if (swap &amp;&amp; swap.tagName == node.tagName)
    {
        module.swapNode(swap);
        PositionElement(menu,menuLink,false,true);
    }
    src.focus();
} 

ノード入れ替えのCSSは、モジュール及び小さなメニューのサイズや色の調整だけで、前のツリーの例と大きな違いはない。

コード例:


ul#swapper { margin:0px; padding:0px; list-item-style:none; }
ul#swapper li { padding:0; margin:1em; list-style:none; height:5em; width:15em; 
    border:1px solid black; }
ul#swapper li a { color:white; text-decoration:none; font-size:90%; }

ul#swapper li div.module_header { text-align:right; padding:0 0.2em; }
ul#swapper li div.module_body { padding:0.2em; }

ul#swapper ul.menu { padding:0; margin:0; list-style:none; background-color:#eeeeee; 
    height:auto; position:absolute; text-align:left; border:1px solid gray; display:none; }
ul#swapper ul.menu li { height:auto; border:none; margin:0; text-align:left; 
    font-weight:normal; width:5em; }
ul#swapper ul.menu li a { text-decoration:none; color:black; padding:0 0.1em; 
    display:block; width:100%; } 

検証

チェックポイント

  1. ドラッグアンドドロップで再配置可能なウェブユニット内のすべてのコンポーネントを探す。

  2. リンクのリストで構成されたメニューでも、それらが再配置可能なメカニズムがあるかどうかもチェックする。

  3. メニューがDOM内の再配置可能な項目の中に含まれているかをチェックする。

  4. 再配置のスクリプトはリンクのonclickイベントだけをトリガーにしているかをチェックする。

  5. 視覚的にだけではなく、項目がDOMの中でも再配置されているかをチェックする。

判定基準

  • 2.~5.を満たしている。

この達成方法が「十分な達成方法」の一つである場合、このチェックポイントや判定基準を満たしていなければ、それはこの達成方法が正しく用いられていないことを意味するが、必ずしも達成基準を満たしていないことにはならない。場合によっては、別の達成方法によってその達成基準が満たされていることもありうる。


SCR28: コンテンツのブロックをバイパスするために、展開可能及び折り畳み可能なメニューを使用する

適用(対象)

クライアントサイド・スクリプティングを提供するウェブコンテンツ技術

これは、次の達成基準に関連する達成方法である:

解説

この達成方法は、繰り返される構成要素を利用者のコントロールの下でメニューを展開したり折りたたんだりできるメニューの中に置くことで、その構成要素をスキップできるようにする。利用者は、メニューを折りたたむことで繰り返される構成要素をスキップできる。利用者は、メニューの要素を隠したり削除したりするユーザインタフェースを呼び出すことができる。関連情報には、ナビゲーションをスキップするメカニズムを提供するために利用できるメニュー、ツールバー及びツリーの達成方法をいくつか挙げている。

注記: 類似の方法は、サーバーサイドスクリプティングを用いて修正後のウェブページを読み込むことでも実装できる。

事例

事例 1

ウェブページの先頭にあるナビゲーションリンクは、すべてHTML、CSS及びJavaScriptを用いて実装されているメニュー項目である。ナビゲーションバーが展開しているとき、ナビゲーションのリンクは利用可能になっている。ナビゲーションバーがたたまれているとき、リンクは利用不可能である。

コード例:


...

  <script type="text/javascript">
  function toggle(id){
    var n = document.getElementById(id);
    n.style.display =  (n.style.display != 'none' ? 'none' : '' );
  }
  </script>

...

  <a href="#" onclick="toggle("navbar")">ナビゲーションバー切り替え</a>

  <ul> id="navbar">
  <li><a href="http://target1.html">リンク 1</a></li>
  <li><a href="http://target2.html">リンク 2</a></li>
  <li><a href="http://target3.html">リンク 3</a></li>
  <li><a href="http://target4.html">リンク 4</a></li>
  </ul>

... 

このコードの実装サンプル:ナビゲーションバーをリンクで切り替える

事例 2

一連のウェブページのための目次はそれぞれのページの先頭近くで繰り返される。目次の先頭にあるボタンで、利用者はそれを消したり復元したりできる。

コード例:


...

   <script type="text/javascript">
  function toggle(id){
    var n = document.getElementById(id);
    n.style.display =  (n.style.display != 'none' ? 'none' : '' );
  }
  </script>

  ...

  <button onclick="return toggle('toc');">目次切り替え</button>
  <div id="toc">
    ...
  </div>

...

このコードの実装サンプル:目次をボタンで切り替える

参考リソース

この参考リソースは、あくまでも情報提供のみが目的であり、推薦などを意味するものではない。

検証

チェックポイント

  1. ユーザインタフェースコントロールで、繰り返されるコンテンツを展開したり折りたたんだりできるかをチェックする。

  2. コンテンツが展開されたとき、それがプログラムで解釈可能なコンテンツに含まれていて、論理的な場所で読み上げ順序があるかをチェックする。

  3. コンテンツが折りたたまれているとき、それがプログラムで解釈可能でない部分にあることをチェックする。

判定基準

  • 上記のすべての項目を満たしている。

この達成方法が「十分な達成方法」の一つである場合、このチェックポイントや判定基準を満たしていなければ、それはこの達成方法が正しく用いられていないことを意味するが、必ずしも達成基準を満たしていないことにはならない。場合によっては、別の達成方法によってその達成基準が満たされていることもありうる。


SCR29: 静的なHTML要素にキーボード操作可能なアクションを追加する

適用(対象)

HTML 及び XHTML、スクリプト

これは、次の達成基準に関連する達成方法である:

ユーザエージェント及び支援技術によるサポート

SCR29 に関するユーザエージェントサポートノート (英語)を参照のこと。

解説

この達成方法の目的は、 divspan などの静的な HTML 要素により実行されるユーザインターフェース コントロールにキーボードアクセスを提供する方法を示すことである。この達成方法は tabindex 属性を設定することで要素をフォーカス可能にし、onclick ハンドラに加えて onkeyup 又は onkeypress ハンドラを提供することでキーボードから動作を実行することができるようにするものである。

tabindex 属性の値が 0 の際、要素はキーボードでフォーカス可能であり、文書のタブ順序に含まれる。tabindex 属性の値が -1 の際、要素はタブ移動できないが、element.focus() を使用することによりフォーカスをプログラムで制御できる。

静的な HTML 要素にはそれらに関連した動作がないため、スクリプトが利用できない環境に対する、代替としての実装又は説明を提供することはできない。この達成方法はクライアントサイド スクリプティングが利用できる環境でのみ使用されるべきである。

注記: そのようなユーザインターフェース コントロールは SC 4.1.2 を達成しなければならない。ユーザインターフェース コントロールの役割、名前及び状態についての情報がないままこの達成基準を適用する場合、失敗例 F59 に該当し、スクリプトを用いて、HTML の div 要素又は span 要素をユーザインタフェースのコントロールにしたことによる達成基準 4.1.2 の失敗例となる。

事例

事例 1: div要素にJavaScriptによるアクションを追加する

ページにある div 要素には一意の id a属性及び値が 0 の tabindex 属性が付与されている。スクリプトはドキュメントオブジェクトモデル(DOM)を利用し、idによって div 要素を見つけ onclick ハンドラ及び onkeyup ハンドラを追加する。onkeyup ハンドラはエンターキーが押下された際、アクションを実行する。div 要素を見つけて変更するには、div 要素が DOM の中に読み込まれた状態でなければならないことに注意する。これは、通常、body要素の onload イベントでスクリプトを呼び出すことで達成される。イベントハンドラを追加するスクリプトはユーザエージェントがJavaScriptをサポートし、かつ有効にしている場合にのみ実行される。

コード例:


...
<script type="text/javascript">
 // これはアクションを実行する関数である。このシンプルな例はメッセージを開閉する。
 function doSomething(event) {
   var msg=document.getElementById("message");
   msg.style.display = msg.style.display=="none" ? "" : "none";
   // リンクのhref属性が実行されないよう、関数からfalseを返す
   return false;
 }
 // これはエンターキーが押された際にアクションが実行される関数である。
 function doSomethingOnEnter(event) {
   var key = 0;
   // window.event 又はイベントオブジェクトが使用されているかに応じて押されたキーを判定する。
   if (window.event) {
     key = window.event.keyCode;
   } else if (event) {
     key = event.keyCode;
   }
   // エンターキーが押されたか?
   if (key == 13) {
     return doSomething(event);
   } 
   // イベントが処理されなかったため、trueを返す
   return true;
 }
 // このsetUpActions()関数は存在するdiv要素にonclick及びonkeyupイベントハンドラを設定するために呼び出されなければならない。
 // この関数はid="active"の付与されたdiv要素がDOMに読み込まれた後に呼び出されなければならない。
 // この例では、setUpActions()関数はbody要素のonloadイベントから呼び出されている。
 function setUpActions() {
   // divオブジェクトを取得する
   var active=document.getElementById("active");
   // onclickハンドラをオブジェクトに割り当てる
   // 関数が返された後、href属性を止めるため、onclickハンドラからfalseを返すことが重要である
   active.onclick=doSomething;
   // onkeyupハンドラをオブジェクトに割り当てる
   active.onkeyup=doSomethingOnEnter;
 }
 </script>

 <body onload="setUpActions();">
 <p>javascriptの動作を用いて変更をもたらすリンク:</p>
 <div>
  <span id="active" tabindex="0">何かをする</span>
 </div>
 <div id="message">こんにちは世界</div>
...

参考リソース

この参考リソースは、あくまでも情報提供のみが目的であり、推薦などを意味するものではない。

検証

チェックポイント

スクリプトをサポートするユーザエージェントで:

  1. マウスを用い、コントロールをクリックする。

  2. スクリプトのアクションが正しく実行される。

  3. キーボードでコントロールに移動したり、フォーカスを与えたりできる。

  4. キーボードのフォーカスをコントロールにセットする。

  5. Enterキーを押すことで、スクリプトのアクションを呼び出すことができる。

判定基準

  • チェックポイント全てを満たしている。

この達成方法が「十分な達成方法」の一つである場合、このチェックポイントや判定基準を満たしていなければ、それはこの達成方法が正しく用いられていないことを意味するが、必ずしも達成基準を満たしていないことにはならない。場合によっては、別の達成方法によってその達成基準が満たされていることもありうる。


SCR30: リンクのラベルを変更するために、スクリプトを使用する

適用(対象)

HTML及びXHTMLで使用されるクライアントサイドスクリプト

これは、次の達成基準に関連する達成方法である:

解説

この達成方法の目的は、リンクが文脈以外でも理解可能になるように、追加情報をリンクテキストに加えることを利用者が選択できるようにすることである。

一部の利用者は、リンクの文脈を参照する必要がないように、リンクがすべてを含んでいることを好む。別の利用者は、それぞれのリンクに文脈に関する情報が含まれていると、反復されてサイトの使い勝手が低下すると感じている。支援技術の利用者の間では、どちらが好ましいかに関して、ワーキンググループへのフィードバックは分かれている。この達成方法は、利用者自身にとって良い方法を選ぶことを可能にする。

どのようなリンクの目的を理解する場合でも追加の文脈が必要とならないようにするため、そのページのリンクのリンクテキストを展開するページの先頭近くにリンクが提供される。展開されるリンクの目的がそのリンクテキストから、常に直接理解可能でなければならない。

この達成方法では、現在表示されているページのリンクだけを展開する。利用者がそのサイトに対して1度だけ設定を行えば良いようにするために、設定情報をCookie又はサーバーサイドのユーザプロファイルに保存することも可能であり、場合によってはそれが望ましい。

事例

事例 1

この例では、JavaScript を用いて直接リンクのテキストに文脈上の情報を追加する。linkクラスはどのテキストを追加するかを決定する。「リンクを展開する」リンクが選択されたとき、ページ内のそれぞれのリンクにテキストを追加すべきかがテストされる。

コード例:

...
<script type="text/javascript">
var expanded = false;
var linkContext = {
	"hist":" 版 Webの歴史",
	"cook":" 版 Cooking for Nerds"
};

function doExpand() {
	var links = document.links;
	
	for (link of links) {
		var cn = link.className;
		if (linkContext[cn]) {
			span = link.appendChild(document.createElement("span"));
			span.setAttribute("class", "linkexpansion");
			span.appendChild(document.createTextNode(linkContext[cn]));
		}
	}
	objUpdate = document.getElementById('expand');
	if (objUpdate)
	{
		objUpdate.childNodes[0].nodeValue = "リンクをたたむ";
	}
	expanded = true;
}

function doCollapse() {
	objUpdate = document.getElementById('expand');
	var spans = document.getElementsByTagName("span");
	var span;

	// リンク一式を戻り、文頭から削除することで配列の添え数を変更する
	// そして処理を乱す
	for (i = spans.length - 1; i >= 0; i--) {
		span = spans[i];
		if (span.getAttribute("class") == "linkexpansion")
			span.parentNode.removeChild(span);
	}
	if (objUpdate)
	{
		objUpdate.childNodes[0].nodeValue = "リンクを展開する";
	}
	expanded = false;
}

function toggle() {
	if (expanded) doCollapse();
	else doExpand();
}
</script>

<h1>本のダウンロード</h1>
<p><a href="#" onclick="doExpand();">リンクを展開する</a></p>

<ul>
<li>Webの歴史:
<a href="history.docx" class="hist">Word</a>, 
<a href="history.pdf" class="hist">PDF</a>, 
<a href="history.html" class="hist">HTML</a>
</li>

<li>Cooking for Nerds:
<a href="history.docx" class="cook">Word</a>, 
<a href="history.pdf" class="cook">PDF</a>, 
<a href="history.html" class="cook">HTML</a>
</li>
</ul>

...

このコードの実装サンプル: 要求に応じてリンクを展開する

検証

チェックポイント

  1. ページの先頭近くに、リンクを展開するリンクがある。

  2. 1. で確認したリンクがリンクテキストだけで見つけられる。

  3. リンクテキストだけで識別できないリンクをページ中から探す。

  4. 1. のコントロールを有効にする

  5. 3. で見つけたリンクの目的が、リンクテキストだけで確認できる。

判定基準

  • 1., 2. 及び 5. を満たしている。

この達成方法が「十分な達成方法」の一つである場合、このチェックポイントや判定基準を満たしていなければ、それはこの達成方法が正しく用いられていないことを意味するが、必ずしも達成基準を満たしていないことにはならない。場合によっては、別の達成方法によってその達成基準が満たされていることもありうる。


SCR31: フォーカスのある要素の背景色又はボーダーを変更するために、スクリプトを使用する

適用(対象)

HTML 及び XHTML、CSS、Script

これは、次の達成基準に関連する達成方法である:

ユーザエージェント及び支援技術によるサポート

SCR31 に関するユーザエージェントサポートノート (英語)を参照のこと。

解説

この達成方法の目的は、コンテンツ制作者がCSSを適用してフォーカス表示を通常よりもより見やすくするためにJavaScriptを使えるようにすることである。要素がフォーカスを受ける時、背景色またはボーダーは視覚的に異なるように変化する。要素からフォーカスがはずれたとき元のスタイルにもどる。この達成方法は:focus疑似クラスをサポートしているいないに関わらず、スクリプトやCSSをサポートしているどんなHTMLのユーザエージェントでも用いることができる。

事例

事例 1

この事例において、リンクにフォーカスが当たった時、背景は黄色に変わる。フォーカスがはずれたとき、黄色ではなくなる。もしリンクに背景色がある場合は、スクリプト内で””よりむしろその色を用いることに注意する。

コード例:

...
<script>
 function toggleFocus(el)
 {
  el.style.backgroundColor =  el.style.backgroundColor=="yellow" ? "inherit" : "yellow";
 }
</script>

...

<a href="example.html" onfocus="toggleFocus(this)" onblur="toggleFocus(this)">ここにフォーカスを置く</a>
...

検証

チェックポイント

  1. キーボード操作でページ内の各要素にタブ移動する。

  2. フォーカス表示が視覚的に認識可能である。

判定基準

  • 2.を満たしている。

この達成方法が「十分な達成方法」の一つである場合、このチェックポイントや判定基準を満たしていなければ、それはこの達成方法が正しく用いられていないことを意味するが、必ずしも達成基準を満たしていないことにはならない。場合によっては、別の達成方法によってその達成基準が満たされていることもありうる。


SCR32: クライアントサイドのバリデーションを提供し、DOM を介してエラーテキストを追加する

適用(対象)

HTML又はXHTMLで使用されるスクリプト。

これは、次の達成基準に関連する達成方法である:

解説

この達成方法の目的は、クライアントサイドでフォームフィールドの検証に失敗したときにエラーメッセージを表示する方法について説明することである。アンカー要素はリスト中でエラーメッセージを表示させる際に使用され、検証が必要なフィールドの上に挿入される。フォーカスをエラーメッセージの場所に移し、利用者の注意を引くために、アンカー要素がエラーメッセージに使用される。アンカー要素のhrefは、エラーがみつかったフィールドへのページ内リンクを含む。

配置されたアプリケーションにおいて、もしJavaScriptが無効になっていれば、クライアントサイドの検証は行われない。そのため、この達成方法はスクリプトが適合性において信頼できる、又はサーバーサイドの検証技術があらゆるエラーを発見し、エラーを含むフィールドの情報とともにページを返すように用いられている場合のみ、十分であるといえる。

事例

事例 1

この事例は必須のフィールドを検証し、さらに特定の書式が必要なフィールドを検証する。エラーがみつかったとき、スクリプトはエラーメッセージの一覧をDOMに挿入し、フォーカスをそこへ移動する。

サンプルの画面イメージ:スクリーンショットは、正しく記入が行われていないいくつかのフィールドのエラーメッセージをあらわしている。エラーメッセージはリンクリストでフォームの先頭近くに現れる。

HTML及びJavascriptのコード

これは事例のフォームのHTMLである:

コード例:


<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html lang="ja">
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>    
        <title>フォームの検証</title>
        <link href="css/validate.css" rel="stylesheet" type="text/css"/>
        <script type="text/javascript" src="scripts/validate.js"/>
    </head>
    <body>

        <h1>フォームの検証</h1>

        <p>以下のフォームは、もしスクリプトが利用可能であれば送信前に検証されるが、
		そうでなければサーバー上で検証される。任意と書かれた以外のすべての
		フィールドは必須である。送信時にエラーがみつかった場合、フォームはキャンセルされて
		エラー一覧がフォームの先頭に表示される。</p>

        <p> 下に貴方の情報を入力してください。 </p>

        <h2>フォームの検証</h2>

        <form id="personalform" method="post" action="index.php">
            <div class="validationerrors"/>
            <fieldset>
                <legend>個人情報詳細</legend>
                <p>
                    <label for="forename">名前を入力してください</label>
                    <input type="text" size="20" name="forename" id="forename" class="string"
                        value=""/>
                </p>
                <p>
                    <label for="age">年齢を入力してください</label>
                    <input type="text" size="20" name="age" id="age" class="number" value=""/>
                </p>
                <p>
                    <label for="email">電子メールアドレスを入力してください</label>
                    <input type="text" size="20" name="email" id="email" class="email" value=""/>
                </p>
            </fieldset>
            <p>
                <input type="submit" name="signup" value="登録"/>
            </p>
        </form>
        <h2>2番目のフォーム</h2>
        <form id="secondform" method="post" action="index.php#focuspoint">
            <div class="validationerrors"/>
            <fieldset>
                <legend>2番目のフォームの詳細</legend>
                <p>
                    <label for="suggestion">提案内容を入力</label>
                    <input type="text" size="20" name="suggestion" id="suggestion" 
                      class="string" value=""/>
                </p>
                <p>
                    <label for="optemail">貴方のメールアドレスを入力してください(任意)</label>
                    <input type="text" size="20" name="optemail" id="optemail"
                        class="optional email" value=""/>
                </p>
                <p>
                    <label for="rating">この提案を評価してください</label>
                    <input type="text" size="20" name="rating" id="rating" 
                      class="number" value=""/>
                </p>
                <p>
                    <label for="jibberish">合言葉を入力してください(任意)</label>
                    <input type="text" size="20" name="jibberish" id="jibberish" value=""/>
                </p>

            </fieldset>
            <p>
                <input type="submit" name="submit" value="提案の追加"/>
            </p>
        </form>
    </body>
</html>

以下は検証を行ってエラーメッセージを挿入するJavaScriptである:

コード例:


window.onload = initialise;

function initialise()
{
   var objForms = document.getElementsByTagName('form');
   var iCounter;

   // フォームそれぞれにイベント・ハンドラを追加
   for (iCounter=0; iCounter<objForms.length; iCounter++)
   {
      objForms[iCounter].onsubmit = function(){return validateForm(this);};
   }
}


// フォームのイベント・ハンドラ
function validateForm(objForm)
{
   var arClass = [];
   var iErrors = 0;
   var objField = objForm.getElementsByTagName('input');
   var objLabel = objForm.getElementsByTagName('label');
   var objList = document.createElement('ol');
   var objError, objExisting, objNew, objTitle, objParagraph, objAnchor, objPosition;
   var strLinkID, iFieldCounter, iClassCounter, iCounter;

   // 部分識別子を固有にするため、
   // フォームのid又はnameを取得する
   if (objForm.id)
   {
      strLinkID = objForm.id + 'ErrorID';
   }
   else
   {
      strLinkID = objForm.name + 'ErrorID';
   }

   // validationクラスを探索するため、inputフォーム・コントロールをループする
   for (iFieldCounter=0; iFieldCounter<objField.length; iFieldCounter++)
   {
      // フィールドのクラスを取得し、適切なクラスを探す
      arClass = objField[iFieldCounter].className.split(' ');
      for (iClassCounter=0; iClassCounter<arClass.length; iClassCounter++)
      {
         switch (arClass[iClassCounter])
         {
            case 'string':
               if (!isString(objField[iFieldCounter].value, arClass))
               {
                  if (iErrors === 0)
                  {
                     logError(objField[iFieldCounter], objLabel, objList, strLinkID);
                  }
                  else
                  {
                     logError(objField[iFieldCounter], objLabel, objList, '');
                  }
                  iErrors++;
               }
               break;
            case 'number':
               if (!isNumber(objField[iFieldCounter].value, arClass))
               {
                  if (iErrors === 0)
                  {
                     logError(objField[iFieldCounter], objLabel, objList, strLinkID);
                  }
                  else
                  {
                     logError(objField[iFieldCounter], objLabel, objList, '');
                  }
                  iErrors++;
               }
               break;

            case 'email' :
               if (!isEmail(objField[iFieldCounter].value, arClass))
               {
                  if (iErrors === 0)
                  {
                     logError(objField[iFieldCounter], objLabel, objList, strLinkID);
                  }
                  else
                  {
                     logError(objField[iFieldCounter], objLabel, objList, '');
                  }
                  iErrors++;
               }
               break;
         }
      }
   }

   if (iErrors > 0)
   {
      // validではない場合、エラーメッセージを表示する
      objError = objForm.getElementsByTagName('div');
      
      // 存在しているエラーを探す
      for (iCounter=0; iCounter<objError.length; iCounter++)
      {
         if (objError[iCounter].className == 'validationerrors')
         {
            objExisting = objError[iCounter];
         }
      }

      objNew = document.createElement('div');
      objTitle = document.createElement('h2');
      objParagraph = document.createElement('p');
      objAnchor = document.createElement('a');

      if (iErrors == 1)
      {
         objAnchor.appendChild(document.createTextNode('送信した中にエラーが1つあります'));
      }
      else
      {
         objAnchor.appendChild(document.createTextNode('送信した中にエラーが' + iErrors + '個あります'));
      }
      objAnchor.href = '#' + strLinkID;
      objAnchor.className = 'submissionerror';

      objTitle.appendChild(objAnchor);
      objParagraph.appendChild(document.createTextNode('以下をご確認ください'));

      objNew.className = 'validationerrors';

      objNew.appendChild(objTitle);
      objNew.appendChild(objParagraph);
      objNew.appendChild(objList);
      
      // 既にエラーがある場合、新しいエラーと交換する。
      // それ以外の場合、フォームの先頭に新しいエラーを追加する。
      if (objExisting)
      {
         objExisting.parentNode.replaceChild(objNew, objExisting);
      }
      else
      {
         objPosition = objForm.firstChild;
         objForm.insertBefore(objNew, objPosition);
      }

      // 待ち時間の設定
      setTimeout(function() { objAnchor.focus(); }, 50);
      
      // フォームを送信しない
      objForm.submitAllowed = false;
      return false;
   }

   // フォームを送信
   return true;
}

// 問題のあるフィールドコントロールを指すリスト項目にリンクを追加する関数
function addError(objList, strError, strID, strErrorID)
{
   var objListItem = document.createElement('li');
   var objAnchor = document.createElement('a');
   
   // フォーム・コントロールへの部分識別子
   objAnchor.href='#' + strID;

   // エラーの見出しに向けたターゲットにする
   if (strErrorID.length > 0)
   {
      objAnchor.id = strErrorID;
   }

   // エラーメッセージ用のラベルプロンプトを使う
   objAnchor.appendChild(document.createTextNode(strError));
   // フォーム・コントロールにフォーカスを当てるために、キーボード及びマウスイベントを追加する
   objAnchor.onclick = function(event){return focusFormField(this, event);};
   objAnchor.onkeypress = function(event){return focusFormField(this, event);};
   objListItem.appendChild(objAnchor);
   objList.appendChild(objListItem);
}

function focusFormField(objAnchor, objEvent)
{
   var strFormField, objForm;

   // キーボードでもリンクが機能するようにする
   if (objEvent &amp;&amp; objEvent.type == 'keypress')
   {
      if (objEvent.keyCode != 13 &amp;&amp; objEvent.keyCode != 32)
      {
         return true;
      }
   }

   // フォーム・コントロールにフォーカスを当てる
   strFormField = objAnchor.href.match(/[^#]\w*$/);
   objForm = getForm(strFormField);
   objForm[strFormField].focus();
   return false;
}

// 与えられたフォームフィールドの名前から、フォーム要素を返す関数
function getForm(strField)
{
   var objElement = document.getElementById(strField);

   // 適切なフォームを探す
   do
   {
      objElement = objElement.parentNode;
   } while (!objElement.tagName.match(/form/i) &amp;&amp; objElement.parentNode);

   return objElement;
}

// リスト中のエラーを記録する関数
function logError(objField, objLabel, objList, strErrorID)
{
   var iCounter, strError;

   // エラープロンプトのラベルを探す
   for (iCounter=0; iCounter<objLabel.length; iCounter++)
   {
      if (objLabel[iCounter].htmlFor == objField.id)
      {
         strError = objLabel[iCounter].firstChild.nodeValue;
      }
   }

   addError(objList, strError, objField.id, strErrorID);
}

// 検証ルーティン - 要求事項として

function isString(strValue, arClass)
{
   var bValid = (typeof strValue == 'string' &amp;&amp; strValue.replace(/^\s*|\s*$/g, '') 
     !== '' &amp;&amp; isNaN(strValue));

   return checkOptional(bValid, strValue, arClass);
}

function isEmail(strValue, arClass)
{
   var objRE = /^[\w-\.\']{1,}\@([\da-zA-Z\-]{1,}\.){1,}[\da-zA-Z\-]{2,}$/;
   var bValid = objRE.test(strValue);

   return checkOptional(bValid, strValue, arClass);
}

function isNumber(strValue, arClass)
{
   var bValid = (!isNaN(strValue) &amp;&amp; strValue.replace(/^\s*|\s*$/g, '') !== '');

   return checkOptional(bValid, strValue, arClass);
}

function checkOptional(bValid, strValue, arClass)
{
   var bOptional = false;
   var iCounter;

   // optionalについて確認
   for (iCounter=0; iCounter<arClass.length; iCounter++)
   {
      if (arClass[iCounter] == 'optional')
      {
         bOptional = true;
      }
   }

   if (bOptional &amp;&amp; strValue.replace(/^\s*|\s*$/g, '') === '')
   {
      return true;
   }

   return bValid;
   }

このコードの実装サンプルは、PHP、JavaScript、CSS及びXHTMLで実装されている:フォーム検証の例

検証

チェックポイント

アンカータグと上記の達成方法による適切なスクリプトを用いて、エラーメッセージを作成する。

  1. ページを読み込む。

  2. エラーメッセージと結びつけられたフィールドに適切な値を入力し、エラーメッセージが表示されない。

  3. エラーメッセージと結びつけられたフィールドに不適切な値を入力し、そのフィールドに適したエラーメッセージが表示される。

  4. エラーメッセージにフォーカスが当たる。

  5. 表示されたエラーメッセージと関連するフィールドに適切な値を入力し、エラーメッセージがなくなる。

  6. アンカータグによってエラーメッセージと関連付けられたすべてのフィールドに対して、繰り返す。

注記: 上記の手順を、支援技術を用いて実行することも推奨する。

判定基準

  • 2、3、4 及び 5 の全てを満たしている。

この達成方法が「十分な達成方法」の一つである場合、このチェックポイントや判定基準を満たしていなければ、それはこの達成方法が正しく用いられていないことを意味するが、必ずしも達成基準を満たしていないことにはならない。場合によっては、別の達成方法によってその達成基準が満たされていることもありうる。


SCR33: スクリプトを用いてコンテンツをスクロールし、それを一時停止できるメカニズムを提供する

適用(対象)

スクリプトでコントロールされる、コンテンツのスクロールをサポートするウェブコンテンツ技術

これは、次の達成基準に関連する達成方法である:

解説

この達成方法の目的は、スクロールするコンテンツがスクリプトで作成されている場合に、利用者にそのスクロールを停止する手段を提供することである。スクロールするコンテンツは、ロービジョンや認知障害の利用者にとって読みにくかったり、全く読めなかったりする。また、動くものは、一部の人々にとって、ウェブページのほかの部分に集中することへの妨げとなる。

事例

事例 1

この例では、CSS及びJavaScriptを用いて、いくつかのテキストを視覚的にスクロールさせている。スクロールの移動を停止するためのリンクが含まれている。

この方法では、JavaScript又はCSSがサポートされていないか有効になっていないときは、すべてのテキストを表示し、リンクを省略する。

下のコードは、webSemanticによるアクセシブルなスクローラー(2008年7月)の修正版である。

XHTML部分:

コード例:

...
<div id="scroller">
<p id="tag">このテキストはスクロールし、JavaScript及びCSSが
サポートされていて有効なときは、停止/スクロールのリンクが提供される。</p>
</div>
...

CSS部分:

コード例:

...
body {font:1em verdana,sans-serif; color:#000; margin:0}

/* position:relative及びoverflow:hiddenは必須 */
#scroller { position:relative; overflow:hidden; width:15em; border:1px solid #008080; }

/* スクロールするテキスト用のフォーマットを追加 */
#tag { margin:2px 0; }

/* #testPは#tagのテキスト変更に関するプロパティを全て含む */
#testP { visibility:hidden; position:absolute; white-space:nowrap; } 

/* ページ先頭の目印として利用され、かつ幅を制限する */
#top { width:350px; margin:auto; }
...

JavaScript部分:

コード例:


var speed=50        // スクロール速度
var step=3          // 動きのスムーズ度合い
var StartActionText= "Scroll"  // 開始させるリンクのテキスト
var StopActionText = "Pause"   // 停止させるリンクのテキスト

var x, scroll, divW, sText=""

function onclickIE(idAttr,handler,call){
  if ((document.all)&amp;&amp;(document.getElementById)){idAttr[handler]="Javascript:"+call}
}

function addLink(id,call,txt){
  var e=document.createElement('a')
  e.setAttribute('href',call)
  var linktext=document.createTextNode(txt)
  e.appendChild(linktext)
  document.getElementById(id).appendChild(e)
}

function getElementStyle() {
    var elem = document.getElementById('scroller');
    if (elem.currentStyle) {
        return elem.currentStyle.overflow;
    } else if (window.getComputedStyle) {
        var compStyle = window.getComputedStyle(elem, '');
        return compStyle.getPropertyValue("overflow");
    }
    return "";
}

function addControls(){
// 最初にCSSサポートをテスト
// style要素又は外部ファイルで定義されたoverflowプロパティ値をテスト
if (getElementStyle()=="hidden") {
  var f=document.createElement('div');
  f.setAttribute('id','controls');
  document.getElementById('scroller').parentNode.appendChild(f);
  addLink('controls','Javascript:clickAction(0)',StopActionText);
  onclickIE(document.getElementById('controls').childNodes[0],"href",'clickAction(0)');
  document.getElementById('controls').style.display='block';
  }
}

function stopScroller(){clearTimeout(scroll)}

function setAction(callvalue,txt){
  var c=document.getElementById('controls')
  c.childNodes[0].setAttribute('href','Javascript:clickAction('+callvalue+')')
  onclickIE(document.getElementById('controls').childNodes[0],"href",'clickAction

('+callvalue+')')
  c.childNodes[0].firstChild.nodeValue=txt
}

function clickAction(no){
  switch(no) {
    case 0:
      stopScroller();
      setAction(1,StartActionText);
      break;
    case 1:
      startScroller();
      setAction(0,StopActionText);
  }
}

function startScroller(){
  document.getElementById('tag').style.whiteSpace='nowrap'
  var p=document.createElement('p')
  p.id='testP'
  p.style.fontSize='25%' //mozilla向け修正 使用する前に4倍する
  x-=step
  if (document.getElementById('tag').className) p.className=document.getElementById

('tag').className
  p.appendChild(document.createTextNode(sText))
  document.body.appendChild(p)
  pw=p.offsetWidth
  document.body.removeChild(p)
  if (x<(pw*4)*-1){x=divW}
  document.getElementById('tag').style.left=x+'px'
  scroll=setTimeout('startScroller()',speed)
}

function initScroller(){
  if (document.getElementById &amp;&amp; document.createElement &amp;&amp; document.body.appendChild) {
    addControls();
    divW=document.getElementById('scroller').offsetWidth;
    x=divW;
    document.getElementById('tag').style.position='relative';
    document.getElementById('tag').style.left=divW+'px';
    var ss=document.getElementById('tag').childNodes;
    for (i=0;i<ss.length;i++) {sText+=ss[i].nodeValue+" "};
    scroll=setTimeout('startScroller()',speed);
  }
}

function addLoadEvent(func) {
  if (!document.getElementById | !document.getElementsByTagName) return
  var oldonload = window.onload
  if (typeof window.onload != 'function') {
    window.onload = func;
  } else {
    window.onload = function() {
      oldonload()
      func()
    }
  }
}

addLoadEvent(initScroller)

参考リソース

この参考リソースは、あくまでも情報提供のみが目的であり、推薦などを意味するものではない。

検証

チェックポイント

  1. スクロールするコンテンツを停止する仕組みが提供されている。

  2. 停止する仕組みを用いて、コンテンツのスクロールが停止する。

  3. スクロールが停止し、自動的に再起動しない。

  4. 停止中のコンテンツを再起動できる仕組みが提供されている。

  5. 提供されている再起動の仕組みを用いて、コンテンツのスクロールを再起動する。

  6. 停止していた位置からスクロールが再開される。

判定基準

  • 3.及び6.を満たしている。

この達成方法が「十分な達成方法」の一つである場合、このチェックポイントや判定基準を満たしていなければ、それはこの達成方法が正しく用いられていないことを意味するが、必ずしも達成基準を満たしていないことにはならない。場合によっては、別の達成方法によってその達成基準が満たされていることもありうる。


SCR34: テキストサイズに応じて拡大するように、サイズ及びポジションを定める

適用(対象)

クライアントサイド・スクリプティング

これは、次の達成基準に関連する達成方法である:

ユーザエージェント及び支援技術によるサポート

SCR34 に関するユーザエージェントサポートノート (英語)を参照のこと。

解説

この達成方法の目的は、文字サイズが縮小・拡大されるのに従って、適切に拡大・縮小するように要素のサイズ及びポジションを定めることである。

ここに要素のサイズとポジションを決めるJavaScriptの4つプロパティがある:

  • offsetHeight (ピクセルでの要素の高さ)

  • offsetWidth (ピクセルでの要素の幅)

  • offsetLeft (ピクセルでの親要素(offsetParent)の左からの距離)

  • offsetTop (ピクセルでの親要素(offsetParent)の上からの距離)

offsetHeightoffsetWidthを用いて高さや幅を定めることは簡単である、しかし、オブジェクトの左とトップの位置を絶対配置の値として定める時、親要素を考える必要がある。下記において、calculatePosition関数は、要素におけるすべての親ノードの最終的な値が決定するまで繰り返されている。 その関数はobjElement(当該の要素の名前)とオフセットプロパティ(offsetLeft又はoffsetTop)の2つの引数を取っている。

事例

事例 1

Javascriptの関数:

コード例:


function calculatePosition(objElement, strOffset)
{
    var iOffset = 0;

    if (objElement.offsetParent)
    {
        do 
        {
            iOffset += objElement[strOffset];
            objElement = objElement.offsetParent;
        } while (objElement);
    }

    return iOffset;
}

次の事例は、上の関数がオブジェクトを、参照オブジェクトの下、かつ、左から同じ距離に配置するために用いられていることを示している:

コード例:


// Get a reference object
var objReference = document.getElementById('refobject');
// Get the object to be aligned
var objAlign = document.getElementById('lineup');

objAlign.style.position = 'absolute';
objAlign.style.left = calculatePosition(objReference, 'offsetLeft') + 'px';
objAlign.style.top = calculatePosition(objReference, 'offsetTop') + objReference.offsetHeight + 'px';

参考リソース

この参考リソースは、あくまでも情報提供のみが目的であり、推薦などを意味するものではない。

検証

チェックポイント

  1. 文字サイズの変更とともにテキストコンテナのサイズを調整するように設計されているページを開く。

  2. ブラウザの文字サイズ調節を使って200%のサイズまで大きくする。(ズーム機能は使用しない)

  3. テキストコンテナのサイズが文字サイズに合わせて調整される。

  4. 文字サイズを大きくした結果、どの文字も「切り取られ」たり、見えなくなっていたりしない。

判定基準

  • 3.及び 4.を満たしている。

この達成方法が「十分な達成方法」の一つである場合、このチェックポイントや判定基準を満たしていなければ、それはこの達成方法が正しく用いられていないことを意味するが、必ずしも達成基準を満たしていないことにはならない。場合によっては、別の達成方法によってその達成基準が満たされていることもありうる。


SCR35: アクションをキーボードで操作可能にするために、アンカー及びボタンのonclickイベントを使用する

適用(対象)

HTML又はXHTMLで使用されるスクリプト。

これは、次の達成基準に関連する達成方法である:

解説

この達成方法の目的は、キーボードでアクセス可能なコントロールに加えることで、キーボードでアクセス可能になるスクリプトの関数を呼び出す方法について説明することである。スクリプトによる動きが確実にキーボードから呼び出されるように、それらの動きは「ネイティブに実行可能な」HTML要素(リンク及びボタン)に関連付けられている。これらの要素のonclickイベントは機器に依存していない。「onclick」という表現はマウスに関連付けられているようにも思えるが、onclickイベントは実際のところ、リンク又はボタンのデフォルトの動きにマッピングされている。デフォルトの動きは、利用者がマウスで要素をクリックしたときに発生するが、要素にフォーカスしてEnterキーやスペースキーを押したとき及び、他のアクセシビリティAPI によってトリガーされたときにも発生する。

この達成方法はクライアントサイドスクリプトに依存しているが、スクリプトが利用できない環境に対する、代替としての実装又は説明として意味がある。アンカー要素を使ってJavaScriptによるアクションを呼び出すとき、代替としての実装又は説明はhref属性によって提供される。ボタンを使用するときは、フォームの送信によって提供される。

事例

事例 1

スクリプトを実行するリンクで、スクリプトをサポートしていないブラウザに対して代替手段を持たないもの。この方法は、スクリプトがアクセシビリティ・サポーテッドな技術に依存しているときのみに使用されるべきである。

このリンクからナビゲートしたくないのではあるが、これを実際のリンクにし、適切なイベントを得るために、a要素上のhref属性を使わなければならない。この事例では、我々は「#」をリンクターゲットとして使用しているが、何を使用しても良い。このリンクからナビゲートされることはない。

doStuff()イベントハンドリング関数の最後にある「return false;」は、ブラウザにそのURIへ移動しないよう指示している。それがなければ、ページはスクリプト実行後に再読み込みされることになる。

コード例:


<script> 
function doStuff()
 {
  //do stuff
    return false;
  }
</script>
<a href="#" onclick="return doStuff();">do stuff</a> 

事例 2

スクリプトを実行するリンクであるが、スクリプトが実行可能でなければ他のページに移動させるもの。この方法はスクリプトに依存しないサイトで、移動先がスクリプトと同じ機能を提供している場合にのみ使用される。この例は、hrefが実在するページであるdostuff.htmに設定されていること以外は、事例 1と同じである。dostuff.htmでは、スクリプトと同じ機能を提供しなければならない。doStuff()イベントハンドリング関数の最後にある「return false;」が、ブラウザにそのURIへ移動しないように指示している。そうでなければ、ブラウザはスクリプト実行後にdostuff.htmに移動してしまう。

コード例:


<script> 
function doStuff() 
 {  
  //do stuff  
  return false; 
 }
</script>
<a href="dostuff.htm" onclick="return doStuff();">do stuff</a> 

このコードの実装サンプル:JavaScriptを用いてアクションリンクを作成

事例 3

スクリプトを実行して、かつスクリプトを使わない利用者のためにフォーム送信を代替とするボタン。このアプローチは、スクリプトに依存しないサイトで、フォームの送信がスクリプトと同じ機能を提供できる場合にのみ使用できる。onsubmit="return false;"はフォームから送信されるのを防ぐ。

コード例:


<script>
  function doStuff()
 {
     //do stuff
 }
</script>
<form action="doStuff.aspx" onsubmit="return false;">
 <input type="submit" value="Do Stuff" onclick="doStuff();" />
</form> 

このコードの実装サンプル:JavaScriptを用いてアクションボタンを作成

事例 4

スクリプトを実行するボタンで、input type="image"を用いて実装されているもの。inputには、画像と等価のテキストを提供するために、タイトル属性を追加しなければならないことに注意する。この方法は、スクリプトに依存しているときのみに利用すべきである。

コード例:


<script>
  function doStuff()
  {
     //do stuff
   return false;
  }
</script>
<input type="image" src="stuff.gif" title="Do stuff" onclick="return doStuff();" /> 

事例 5

スクリプトを実行するボタンで、input type="submit"input type="reset"又はinput type="button"のいずれかを用いて実装されているもの。この方法は、スクリプトに依存しているときのみに利用すべきである。

コード例:


<input type="submit" onclick="return doStuff();" value="Do Stuff" />

事例 6

スクリプトを実行するボタンで、 button/buttonを用いて実装されているもの。これは、ボタンの見た目をより詳細に調整したいときに有効である。この特定の例では、ボタンはアイコンとテキストの両方を含んでいる。この方法は、スクリプトに依存しているときのみに利用すべきである。

コード例:


<button onclick="return doStuff();">
 <img src="stuff.gif" alt="stuff icon">
 Do Stuff
</button>

参考リソース

この参考リソースは、あくまでも情報提供のみが目的であり、推薦などを意味するものではない。

検証

チェックポイント

abutton、又はinput要素と関連付けられたすべてのスクリプトのアクション:

  1. スクリプトをサポートするユーザエージェントで:

    • マウスを用い、コントロールをクリックする。

    • スクリプトのアクションが正しく実行される。

    • もしコントロールがアンカー要素なら、アンカー要素のhref属性のURIが呼び出されない。

    • キーボードでコントロールに移動したり、フォーカスを与えたりできる。

    • キーボードのフォーカスをコントロールにセットする。

    • Enterキーを押すことで、スクリプトのアクションを呼び出すことができる。

    • もしコントロールがアンカー要素なら、アンカー要素のhref属性のURIが呼び出されない。

  2. スクリプトをサポートしていないユーザエージェントで:

    • マウスでコントロールをクリックする。

    • もしコントロールがアンカー要素なら、アンカー要素のhref属性のURIが呼び出される。

    • キーボードでコントロールに移動したり、フォーカスを与えたりできる。

    • キーボードのフォーカスをコントロールにセットする。

    • もしコントロールがアンカー要素なら、Enterキーを押すことでアンカー要素のhref属性のURIが呼び出される。

判定基準

  • 上記のチェックポイント全てを満たしている。

この達成方法が「十分な達成方法」の一つである場合、このチェックポイントや判定基準を満たしていなければ、それはこの達成方法が正しく用いられていないことを意味するが、必ずしも達成基準を満たしていないことにはならない。場合によっては、別の達成方法によってその達成基準が満たされていることもありうる。


SCR36: 静的なウィンドウ又はエリアにある、動きのあるテキスト、スクロールするテキスト、又は自動更新されるテキストを利用者が表示できるメカニズムを提供する

適用(対象)

動く、点滅する、又はテキストを更新し、静的なテキスト・ブロックを生成する全てのウェブコンテンツ技術

これは、次の達成基準に関連する達成方法である:

解説

スペースが限られているために、スクロールするテキストを表示するウェブページがある。小さなテキストウィンドウの中でテキストをスクロールさせることにより、その速度にあわせて読むことができる利用者にはコンテンツが利用可能となるが、それよりも速度が読むのが遅い利用者や、支援技術の利用者にとっては問題となる。この達成方法では、動きを止めて、テキスト・ブロック全体を静的に利用可能にするメカニズムを提供する。テキストは別ウィンドウかページ中の(より大きな)セクションで利用可能になるだろう。そうすることで、利用者はテキストを自分の速度で読むことができる。

この達成方法は、動いているテキストが全て同時に画面に表示できない場合(例:長いチャットでの会話)には適用されない。

注記: この達成方法は、不適合のコンテンツのための適合している代替版のページを表示するためのスタイルスイッチの達成方法とあわせて利用できる。詳細については、C29: 適合している代替版を提供するために、スタイル・スイッチャーを使用する (CSS) 及び適合している代替版を理解するを参照のこと。

事例

事例 1: スクロールするテキストを展開する

大きなテキスト・ブロックがページ中の小さなマーキーの範囲をスクロールする。ボタンにより、利用者はスクロールを止め、テキスト・ブロック全体を表示することができる。

注記: このコード例ではCSSとJavaScriptの両方が利用可能で有効になっている必要がある。

CSS部分:

コード例:


#scrollContainer {
        visibility: visible;
        overflow: hidden;
        top: 50px; left: 10px;
        background-color: darkblue;
      }
      .scrolling {
        position: absolute;
        width: 200px;
        height: 50px;
      }
      .notscrolling {
        width: 500px;
        margin:10px;
      }
      #scrollingText {
        top: 0px;
        color: white;
      }
      .scrolling #scrollingText {
        position: absolute;
      }
      </a> 

スクリプト及びHTMLコンテンツ:

コード例:


<script type="text/javascript">

      var tid;
      function init() {
        var st = document.getElementById('scrollingText');
        st.style.top = '0px';
        initScrolling();
      }
      function initScrolling () {
        tid = setInterval('scrollText()', 300);
      }
      function scrollText () {
        var st = document.getElementById('scrollingText');
        if (parseInt(st.style.top) > (st.offsetHeight*(-1) + 8)) {
          st.style.top = (parseInt(st.style.top) - 5) + 'px';
        } else {
          var sc = document.getElementById('scrollContainer');
          st.style.top = parseInt(sc.offsetHeight) + 8 + 'px';
        }
      }
      function toggle() {
        var scr = document.getElementById('scrollContainer');
        if (scr.className == 'scrolling') {
          scr.className = 'notscrolling';
          clearInterval(tid);
           document.getElementById('scrollButton').value="格納";
        } else {
          scr.className = 'scrolling';
          initScrolling();
          document.getElementById('scrollButton').value="展開";
        }
      }
  <input type="button" id="scrollButton" value="展開" onclick="toggle()" />
  <div id="scrollContainer" class="scrolling">
    <div id="scrollingText" class="on">
    .... スクロールするテキスト ...
    </div>
  </div>
... 

このコードの実装サンプル:スクロールするテキストを展開

検証

チェックポイント

この達成方法についての検証項目はない。

この達成方法が「十分な達成方法」の一つである場合、このチェックポイントや判定基準を満たしていなければ、それはこの達成方法が正しく用いられていないことを意味するが、必ずしも達成基準を満たしていないことにはならない。場合によっては、別の達成方法によってその達成基準が満たされていることもありうる。


SCR37: デバイス非依存な方法でカスタム・ダイアログを作成する

適用(対象)

スクリプトで使用されるHTML及びXHTML

これは、次の達成基準に関連する達成方法である:

解説

コンテンツ制作者はしばしば、ブラウザによって提供されるポップアップウインドウを使わずに、独自のダイアログを作成したがる。これは通常、ダイアログのコンテンツをdivの中に収めて、そのdivをコンテンツの上にCSSによる重なり順及び絶対配置を用いて配置するというやり方でおこなわれる。

これらのダイアログをアクセシブルにするには、いくつかの簡単なルールに従う必要がある。

  1. リンクやボタンのonclickイベントからダイアログを起動するスクリプトをトリガーにする。

  2. ダイアログのdivをDocument Object Model (DOM) の中、トリガーした要素の直後に配置する。トリガーした要素がフォーカスを保持し、ダイアログのコンテンツをその要素のあとに挿入することで、ダイアログの中のコンテンツがスクリーンリーダーの読み上げ順序で次になり、タブ順序も次になる。それでも、ダイアログは視覚的にページ上のあらゆる場所に絶対配置できる。これは、下の例のようにダイアログをHTMLの中で作成し、CSSで非表示にする方法又は、トリガーした要素の直後にスクリプトで挿入する方法のどちらでも実装できる。

  3. ダイアログのdiv内部のHTMLが、その他のコンテンツと同じアクセシビリティガイドラインの要件を満たしていることを保証する。

リンクがダイアログを開閉できたり、キーボードのフォーカスが外れるとダイアログが閉じるようにしたりすることはすばらしいが、必ずしも必要なわけではない。

事例

事例 1: ダイアログを開くオプションボタン

この例のHTMLには、トリガーとなる要素、この場合はボタンとダイアログのフレームとして機能するdivがある。

トリガーとなる要素はボタンで、スクリプトはonclickイベントのトリガーである。これは適切なイベントをオペレーティングシステムに送るので、支援技術はDOMの中の変化に気がつくことができる。

この例では、ダイアログ内の送信及びリセットボタンは単純にdivに隠れている。

コード例:

 role="xhtml1">...
<button onclick="TogglePopup(event,true)"
	name="pop0001">オプション</button>

<div class="popover" id="pop0001">
  <h3>並べ替えの情報を編集</h3>
  <form action="default.htm" onsubmit="this.parentNode.style.display='none'; return false;" onreset="this.parentNode.style.display='none'; return false;">
    <fieldset>
      <legend>並び順</legend> 
      <input type="radio" name="order" id="order_alpha" /><label for="order_alpha">アルファベット順</label>
      <input type="radio" name="order" id="order_default" checked="true" /><label for="order_default"&amp;gt既定</label>
    </fieldset>
<div class="buttons">
  <input type="submit" value="OK" />
  <input type="reset" value="キャンセル" />
</div>
</form>

</div>
...

div、見出し、及びform要素はCSSでダイアログに見えるようにスタイル付けされている。

コード例:

...
a { color:blue; }
a.clickPopup img { border:none; width:0; }

div.popover { position:absolute; display:none; border:1px outset; background-color:beige; font-size:80%; background-color:#eeeeee; color:black; }
div.popover h3 { margin:0; padding:0.1em 0.5em; background-color:navy; color:white; }
#pop0001 { width:20em; }
#pop0001 form { margin:0; padding:0.5em; }
#pop0001 fieldset { margin-bottom:0.3em; padding-bottom:0.5em; }
#pop0001 input, #pop0001 label { vertical-align:middle; }
#pop0001 div.buttons { text-align:right; }
#pop0001 div.buttons input { width:6em; }
...

スクリプトはポップアップするdivの表示を切り替え、表示させたり隠したりする。

コード例:

...
function TogglePopup(evt,show)
{
	HarmonizeEvent(evt);
	var src = evt.target;
	if ("click" == evt.type)
	{
		evt.returnValue = false;
	}
	var popID = src.getAttribute("name");
	if (popID)
	{
		var popup = document.getElementById(popID);
		if (popup)
		{
			if (true == show)
			{
				popup.style.display = "block";
			}
			else if (false == show)
			{
				popup.style.display = "none";
			}
			else
			{
				popup.style.display = "block" == popup.style.display ? "none" : "block";
			}
			if ("block" == popup.style.display)
			{
				//window.alert(document.documentElement.scrollHeight);
				popup.style.top = ((document.documentElement.offsetHeight - popup.offsetHeight) / 2 ) + 'px';
				popup.style.left = ((document.documentElement.offsetWidth - popup.offsetWidth) / 2) + 'px';
			}
		}
	}
}

function SubmitForm(elem)
{ 
	elem.parentNode.style.display='none'; 
	return false;
}

function ResetForm(elem)
{ 
	elem.parentNode.style.display='none'; 
	return false;
}
...

このコードの実装サンプル:ダイアログを開くオプションボタン

参考リソース

この参考リソースは、あくまでも情報提供のみが目的であり、推薦などを意味するものではない。

検証

チェックポイント

  1. ページ内のすべての場所から、ダイアログのトリガーとなるもので、ポップアップウインドウでないものを探す。

  2. Tabキーでその場所に移動してEnterキーを押下することで、ダイアログを開くことができる。

  3. 開いたら、タブ順序でダイアログが次の位置にある。

  4. ダイアログがボタン又はリンクのクリックイベントによってトリガーされている。

  5. スクリプトによって生成されたDOMを検証できるツールを用いて、DOM内でダイアログが次にある。

判定基準

  • 2., 3., 4.及び5.を満たしている。

この達成方法が「十分な達成方法」の一つである場合、このチェックポイントや判定基準を満たしていなければ、それはこの達成方法が正しく用いられていないことを意味するが、必ずしも達成基準を満たしていないことにはならない。場合によっては、別の達成方法によってその達成基準が満たされていることもありうる。


SCR38: プログレッシブ・エンハンスメントで設計されたウェブページに対して、適合している代替版を作成する

適用(対象)

HTML with scripting.

これは、次の達成基準に関連する達成方法である:

解説

この達成方法の目的は、プログレッシブエンハンスメントで設計されたウェブページに適合する代替バージョンを提供することである。この達成方法は、スクリプトを用いて達成する方法を次のように示している:

  1. ウェブページの初期拡張バージョンを格納することで、後に拡張されたコンテンツのバージョンに対して「適合した代替バージョン」として機能できるようにし、かつ

  2. すべての拡張されたバージョンのウェブページに対して、利用者がコンテンツを格納された初期拡張の代替バージョンに戻すことができる機能を実装する。

プログレッシブエンハンスメントで設計されたウェブページはサポートされたウェブ技術を HTML 基盤のレイヤーに適用できるようにするため、ウェブ対応機器(サイズ、機能及びソフトウェア)の特徴を検出する。より高度なアクセス機器のさまざまな機能に合わせて拡張バージョンのページが作成される一方で、そのようなウェブページの基本的なコンテンツと機能は、よりシンプルなウェブ対応機器を使用している人なら誰でも HTML 基盤を通じて利用することができる。

現在の代替バージョンのウェブページの要件は次のようになっている: 「注記 4: 様々な技術環境又は利用者層に対応するために、複数の代替バージョンを提供してもよい。この場合、各バージョンは可能なかぎり適合したものでなければならず、適合要件 1を満たすためには、そのうちの一つのバージョンが完全に適合したものでなければならない。」プログレッシブエンハンスメントで設計されたウェブページは、どのバージョンを完全に適合したものとして選ぶかという問題を残しているが、どんな利用者においても不利な状況におかれないようにする。

この課題の解決策の 1 つは、広範囲のウェブ対応機器がコンテンツにアクセス可能なため、拡張前のウェブページ(例: スクリプト、スタイル、HTML ではないプラグインが無効時に作成される HTML のソースコードの DOM の状態)を「完全に適合したバージョン」として選択することである。

注記: この達成方法はすべてのスクリプト、スタイル、プラグインを除外するが、これは WCAG 2.0 に適合するために必須ではないことを示す必要がある。制作者は類似した技術を使用することができるが、還元されたスタイルとスクリプトを「拡張前」のバージョンで保つことができる。

この技術は 1 つのバージョンで適合表明を行う方法を提供するが、制作者は各拡張版のウェブページが可能な限り適合するために作業し続けるべきである。

事例

事例 1: JavaScriptを使用する

この事例は「accToggle.js」ファイル内でJavaScriptを使用し、HTMLソースコードのみで作成された拡張前のウェブページを格納することで、後に拡張されたウェブページの「適合した代替バージョン」として機能させることができる。そして、利用者がウェブページを最初の拡張前の「適合した代替バージョン」に戻せるよう、すべての拡張されたウェブページに切り替えリンクを設置する。注記: 「sayhello.js」ファイルは単なる外部のペイロードファイルの例であり、必要な他の外部スクリプトに置き換えられる。

accToggle.js ファイル内のスクリプトは拡張前のバージョンを格納し、このバージョンの URL に #accessible という接尾辞を付与する。「WCAG 2.0 適合する代替版」という(すべての拡張されたバージョンのページにおいて、body 要素の最初の子要素として設置される)リンクをクリックすることにより、接尾辞に「#accessible」とついたURLに変化し、body 要素と head 要素内のHTMLを拡張前のコードに初期化する。拡張前の状態はリンクから、又はURLをブラウザに直接入力することでアクセスできる。さらに、拡張前の「適合する代替版」にリンクが追加され、利用者がウェブページを拡張版にすることができる(これはブラウザの戻るボタンからでも可能)。

acctoggle.js ソースコード:


window.onload = function(event) {

    // 拡張前のコンテンツを保管する
    var initialHead = document.head.innerHTML;
    var initialBody = document.body.innerHTML;
    var initialURL = location.href;
    
    var runOnce = function() {
         // ページ読み込み毎に実行したいペイロード 例: Google Analytics コード
    }
    
    var setup = function() {
         // 適合している代替版のリンクを作成する

        var toggleEnhanced = document.querySelector("#toggle_enhanced");
        if (toggleEnhanced) {
            toggleEnhanced.outerHTML = "";
        }
        
        var nel = document.createElement("a");
        nel.id = "acctoggle";
        nel.setAttribute("href", "#accessible");
        nel.innerHTML = "WCAG 2.0 に適合している代替版";
        document.body.insertBefore(nel, document.body.firstChild);
        
         // ペイロード
        var s = document.createElement("SCRIPT");
        s.setAttribute("src", "sayhello.js");
        document.querySelector("HEAD").appendChild(s);   
       }
    
    setup();
    runOnce();
    
    window.onpopstate = function(event) {
        if (location.href.indexOf("#accessible") != -1) {
             // コンテンツを拡張前のバージョンに戻す
            document.head.innerHTML = initialHead;
            document.body.innerHTML = initialBody;
            
            // create enhanced version link
            var el = document.createElement("a");
            el.id = "toggle_enhanced";
            el.setAttribute("href", "");
            el.innerHTML = "拡張版";
            var back = function(e) {
                 e.preventDefault();
                 window.history.back();
            }
            el.addEventListener("click", back, false);
            document.body.insertBefore(el, document.body.firstChild);
        }
        if (location.href == initialURL) {
            setup();
        }
    };
}
		 

HTML ウェブページソースコード:


<!DOCTYPE html>
<html lang="ja">
    <head>
        <title>Evaluera Ltd</title>
        <meta charset="UTF-8" />
        <script src="accSwitch.js"></script>
    </head>
    <body> 
        <h1>テストページ</h1>
        <p>発言: <span id="change">さよなら</span></p>
    </body>
</html>			
		 

sayhello.js ソースコード


var change = document.querySelector("#change");
change.innerText = "こんにちは";		
		 

事例 2: EnhanceJS を使用する―プログレッシブエンハンスメントのアプリケーションを改善するために設計された Javascript フレームワーク

EnhanceJS は「高度なスタイルとスクリプトをページに適用する前に、JavaScript の主要な機能と CSS のサポートを最初にテストすることで、プログレッシブエンハンスメントのアプリケーションを改善するように設計された」オープンソースの JavaScript フレームワークである。さらに、デフォルトの EnhanceJS スクリプトは、利用者が拡張前のウェブページの状態に戻すことがでるよう、すべての拡張版のページに自動的に切り替えリンクを作成する。(EnhanceJS でデフォルトで設定されるこれを「低帯域幅版」と呼ぶ)。EnhanceJS ではこの設定は拡張前の状態が「低帯域幅版」ではなく、「WCAG 2.0 の適合している代替版」として認識されるよう変更されている。

HTML コンポーネント:


<!DOCTYPE html>
<html lang="ja">
    <head>
    <script type="text/javascript" src="enhance.js"></script>
    <script type="text/javascript">
        // 機能テストを実行
        enhance({
            loadStyles: [
                "example.css"
            ], 
            loadScripts: [
                "example.js"
            ],
           // 拡張モードで表示されるテスト
          forceFailText: "WCAG 2.0 に適合している代替版",
           // アクセシブルモードで表示されるテスト
          forcePassText: "拡張版"
        });
    </script>
    </head>
    ....

参考リソース

この参考リソースは、あくまでも情報提供のみが目的であり、推薦などを意味するものではない。

検証

チェックポイント

  1. 拡張されたウェブページが「適合している代替版」へのリンクを含んでいる。

  2. 代替バージョンが、オリジナルページの適合している代替版であり、かつ要求された適合レベルで WCAG 2.0 に適合している。

判定基準

  • 1. 及び 2. を満たしている。

この達成方法が「十分な達成方法」の一つである場合、このチェックポイントや判定基準を満たしていなければ、それはこの達成方法が正しく用いられていないことを意味するが、必ずしも達成基準を満たしていないことにはならない。場合によっては、別の達成方法によってその達成基準が満たされていることもありうる。