ストリーミングはほとんどのブラウザと
Developerアプリで視聴できます。
-
Webアクセシビリティの最新情報
カスタムコントロール、SSML、ダイアログ要素を使って、リッチでアクセシブルなWeb Appを構築するテクニックをご覧ください。さまざまな補助機能を解説しますので、Web Appのアクセシビリティをテストする際に役立てることができます。
リソース
関連ビデオ
WWDC21
-
ダウンロード
こんにちは Tylerです WebKit Accessibility Teamのエンジニアです このセッションでは 最新の Webアクセシビリティ に関してお話します はじめに 読み上げ機能などの 補助機能についての 簡単な説明を行い
次にWeb Speech APIと ダイアログ要素内で カスタムのコントロールや SSMLなどのツールを使って リッチでアクセッシブルな Web Appを作る方法を紹介します
まずは補助機能についてです 世界中で7人に1人が 周囲やデバイス Webとの交流が困難な 障害を持っています 年齢やその期間に関わらず さまざまな症状を 患っているかもしれません Appleは最適な方法で デバイスを利用できる 数々のツールを 用意しています VoiceOverやスイッチコントロール そして音声コントロール フルキーボードアクセス など それぞれが異なる デバイスの利用方法を提供します これらのツールについては 昨年のセッション 「iOS Appにおけるフルキーボード アクセスのサポート」をご覧ください
実際にVoiceOverを使い クイズサイトを ナビゲートしてみましょう iPadのトップボタンを3回 押しVoiceOverを有効にします Siri:VoiceOverオン Safari サイドバー表示 ボタン
Tyler:VoiceOverがアクディブになり ページの冒頭をタップします Siri:ポップクイズ Heading レベル1 Tyler:右スワイプで ページ内を移動します Siri:6問中1つ目 8等分の ピザの4分の1は? 2スライス ラジオボタン 4つの1つ目 空白 3スライス 4スライス 6スライス 次の質問ボタン Tyler:Webデベロッパには VoiceOverのように ページをアクセシブルに する多くのツールがあります 例えばSafariには ボタンやh1からh6 table elementsや list elementsなどの セマンティック HTMLの サポートがあります セマンティック HTMLの使用を デフォルトにすれば ブラウザを通じて一貫した アクセシビリティ体験を ユーザーに提供できます しかしセマンティックHTMLでは 十分ではなく JavaScriptを使用しなければ ならない場合があります その場合 補助機能に セマンティックを 正しく伝えるため ARIA属性も 必要になるでしょう そこで2つ目のトピック カスタムのコントロールです 先ほどのピザのクイズを より使いやすいものにしたいとします ラジオボタンをカスタム コントロールに置き換え タップでピザをトレイから 動かせるようにします この場合のマークアップは divとidから始まります
タップやクリックで これを可能にするには click event listenerが必要です id要素を受け入れる コンストラクタをもつ PizzaControl クラスを 作りましょう
要素をIDで取得し click event listenerを追加します
このlistenerがタップの 位置に基づきピザの数を計算し updateと呼ばれる関数に 値をパスしリレンダリングします しかし 誰もがこの機能を 使えるわけではありません
例えばどこをタップすれば いいかわからない 目の不自由な ユーザーだったら? カスタムコンポーネントを 構築する際は さまざまなユーザーを 考慮する必要があります それを念頭に 最初のステップは 「slider」の値をもつrole属性 を与えることです 今回のコントロールには sliderがぴったりです 最小値は0スライス 最大値は8スライス 現在値は4スライスです キーボードなどタッチできない インターフェイス用に 0のtabindexを 追加します
またARIA属性も必要です
aria-valueminと aria-valuemaxは このsliderの最小・最大値を 伝達します
これはrange type inputsの min max attributesに似ています
次にaria-valuenowで 現在値を伝達します
aria-valuetextで 分かりやすい説明を 追加します この場合「4スライス」です
コントロールをフォーカス可能な スライダーとしたところで 補助機能から 受け取る値の処理が必要です iOSではVoiceOverが 指1本の上スワイプで スライダーの増加 そして下スワイプで スライダーの減少に 対応するようになっています これらのジェスチャーに Safariは簡単に対応できます VoiceOverのユーザーが スライダーを上スワイプすると Safariは右矢印キーと 同様にみなします 同じく下スワイプだと 左矢印キーと 同様にみなします これらは実際にキーを 押した時と同じように動作し key event listenersで 処理できます この知識とともに keydown listenerを コントロールに足しましょう 作動したキーが 右矢印か上矢印キーなら 現在値プラス1として コントロールを更新します 同様に作動したキーが 左矢印か下矢印キーなら 現在値マイナス1として コントロールを更新します これはVoiceOverを使う ユーザーだけでなく キーボードでWeb Appに アクセスするユーザーにも 応えることができます event listenersが 出来上がったところで 次は update 関数を 定義しましょう まず 与えられた範囲である 0から8に 値を制限し SliceCountの値を更新します 次にコントロールの ビジュアルおよびARIA表示を 更新します カスタムコンポーネントを 作成する際 ビジュアル表示を更新する時は ARIA表示も更新することを 覚えておきましょう
この場合 aria-valuenowと aria-valuetextの属性を更新し コントロールの新しい値を ユーザーに知らせます
まずaria-valuenowを 現在値に設定します
次にaria-valuetextに わかりやすい説明 「スライスの数+枚」を 入れます 設定が終わったところで クイズのWeb Appに戻り VoiceOverを試してみましょう ピザをタップして フォーカスします Siri:4スライス 変更可能 指1本で上下にスワイプし 値を変更 Tyler:VoiceOverが スライダーの現在の値は 4スライスで 変更可能だと読み上げました その指示に従い上スワイプで スライス数を増やしていきます Siri:5スライス 6スライス Tyler:下スワイプで スライス数を減らします Siri:5スライス 4スライス Tyler:これらの変更によって カスタムスライダー コンポーネントが アクセシブルになりました 次にWeb Speech APIで SSMLを使い さらに豊かな体験を 提供してみましょう Web Speech APIは2つの JavaScriptからなります オーディオインプット用の SpeechRecognitionと オーディオアウトプット用の SpeechSynthesisです
Web Speechは 音声補助機能付き または 音声のみのインターフェイスを Web Appに提供できます
これは マウスやキーボード タッチスクリーンなどを 使用するのが困難な 運動機能に障がいのある方々に 便利です SafariのSpeechSynthesisの新機能として テキストの話し方を調整する SSMLを使用できるようになりました SSMLには多くの能力があります 例えばbreak要素を使って 任意のタイミングで スピーチにポーズを 加えることができます ユーザーに呼吸する指示を 出す時などに便利です
phoneme要素を使って tomayto /tomahtoなどの 発音方法を指定できます
prosody要素を使って 声のピッチや 速さ ボリュームを調節できます これらはSSMLの能力の ごく一部です SSMLの詳細は w3.orgをご覧ください ではSSMLを 実際に使ってみましょう 最後の問題は"the water"の スペイン語の正しい翻訳の ラジオボタンを選択してもらう クイズです ボタンを押して text-to-speechを使って 問題と解答を読み上げ SSMLでスペイン語のフレーズを 現地の言葉で 読み上げるようにすれば 非常に使いやすいものになります まずボタンを作成しますが この絵文字必要ないので span aria-hiddenを trueに指定し 絵文字を隠すことから 始めます
次にwrapWithSSMLという JavaScriptのヘルパー関数で phraseとlocaleを指定します
各フレーズ前にポーズを置くため break 要素でSSMLの ストリングを作成します
prosody要素で デフォルト80%の速さで 読むよう指定します
最後にlang要素で 現地の言葉で話すように 指定します
さらに 「Read Question」ボタンに click event listenerを追加し その中にSSMLストリングを 作成します まずはストリングを speak要素ですべて囲みます
speak要素は synthesis processorsに 中身がすべてSSMLだと 示すため重要です
次にHow do you say "the water" in Spanish? という質問を含めます wrapWithSSMLヘルパー関数を使って 翻訳されるフレーズに強調を与え 米英語のローカル音声で 読むよう指定します
4つの答えにも wrapWithSSMLを使い スペイン語のローカル音声で 読むよう指定します
最後にSSMLで新しい SpeechSynthesisUtterance オブジェクトを作成し window.SpeechSynthesis. speakメソッドに渡して読み上げます
では実際どう動作するか 見てみましょう 最後の問題ページで 「Read question」ボタンを押し 聞いてみます Siri:How do you say "the water" in Spanish? El agua La abuela La abeja El árbol Tyler:SSMLのおかげで 生徒にとって非常に 使いやすくなりました
ウェブでよくあるデザインの もう一つがモーダルです
サインインや登録フォーム 確認ダイアログなどに 使われています
アクセシブルな モーダルを提供する方法の1つが aria-modal属性です aria-modalをtrueに するとSafariは モーダル外のアクセシブルな 要素を無視します 最近ではSafariでdialog要素が サポートされるようになりました dialog要素を使用すると アクセシブルな体験を これまで以上に簡単に提供できます 一般的なフォーカス操作に加え EscapeキーやiOSのスクラブのような 閉じるジェスチャーが 簡単になります それではこの例の 「Show score」ボタンを 結果のダイアログに 変更してみましょう
まずdialog要素の作成が必要です マークアップはこのようになります show scoreボタンで後で参照できるよう dialogにIDを与えます ダイアログのコンテンツを dialogメソッドを含むformで囲みます
これで 今回のボタンのような コントロールで ダイアログを 閉じることができます またモーダル開くのに JavaScriptが必要です dialog要素で showModal()を呼ぶ 「Show Score」ボタンに click event listenerを追加します
では試してみましょう VoiceOverを稼働させ 「Show score」をタップします
Siri:「Show score」ボタン
Tyler:ボタンを押すには 指1本でダブルタップです Siri:スコアを表示 ダイアログ 「Close」ボタン Tyler: ここでモーダルが表示されます 左スワイプで スコアを聞くことができます Siri:全6問正解しました おめでとう! Tyler:右スワイプで 「Close」ボタンに 戻ります Siri:「Close」ボタン Tyler:ダブルタップで モーダルを閉じます Siri:チェックが外れました Tyler:先ほどお話したように iOSのスクラブのジェスチャーを ボックス外で行うことで dialog要素が モーダルを自動的に閉じてくれます ダブルタップで モーダルをまた開きます Siri:「Show score」ボタン Webダイアログ 「Close」ボタン Tyler:そして2本指で 右・左・右に 素早くスクラブします
Siri:「Show score」ボタン Tyler:モーダルが出来上がりましたが さらに向上させることができます モーダルを開いた時 Webダイアログ 「Close」ボタン としか聞こえませんでした この場合 aria-labelまたは aria-labelledb属性で 追加の情報を 補助機能を用いて ユーザーに提供することができます モーダルの内容は短いので クイズの正解数を labelに使いましょう まずモーダルのコンテンツを span idで囲みます modal-content IDを指す dialogに aria-labelledby 属性を加えます
またautofocus属性を 「Close」ボタンに加えることで モーダルの初期フォーカスを 明確にします
これは今回のシンプルな モーダルでデフォルトでしたが モーダルにもっと コンテンツがあったり 複雑であれば 違ったかもしれません
例えばコンテンツが多い モーダルの場合 top-level headingに autofocusを置くべきです モーダルを開発する皆さんに その判断を委ねます
ではVoiceOverを 試してみましょう 「Show score」ボタンを タップしフォーカスします Siri:「Show score」ボタン
Tyler:ダブルタップして押します Siri:全6問正解です おめでとう Webダイアログ 「Close」ボタン Tyler:よくなりましたね aria-labelledbyのおかげで すぐに得点を聞くことができて 「Close」ボタンに フォーカスしているので ダブルタップで モーダルを出られます ではこのセッションの まとめです すべてのユーザーに最高の体験を届ける リッチでアクセシブルな Web Appを作成する技術を 学ぶことができたかと思います これらをSafariでお試しになり バグがあれば WebKitのバグトラッカーで 報告してください 今日はご閲覧 ありがとうございました WWDCをお楽しみください
-
-
3:06 - PizzaControl class with click event listener
class PizzaControl { constructor(id) { this.control = document.getElementById(id); this.sliceCount = 4; this.control.addEventListener("click", (event) => { const newSliceCount = this.computeSliceCount(event); this.update(newSliceCount); }); } }
-
4:23 - PizzaControl HTML markup
<div id="pizza-input" role="slider" tabindex="0" aria-valuemin="0" aria-valuemax="8" aria-valuenow="4" aria-valuetext="4 slices"> </div>
-
5:15 - PizzaControl class with keydown event listener
class PizzaControl { constructor(id) { this.control = document.getElementById(id); this.sliceCount = 4; // …click event listener… this.control.addEventListener("keydown", (event) => { const key = event.key; if (key === "ArrowRight" || key === "ArrowUp") this.update(this.sliceCount + 1); else if (key === "ArrowLeft" || key === "ArrowDown") this.update(this.sliceCount - 1); }); } }
-
5:41 - PizzaControl class update function
class PizzaControl { // …constructor… update(newSliceCount) { this.sliceCount = Math.max(0, Math.min(newSliceCount, 8)); // Visually re-render `this.sliceCount` slices // … // Update the ARIA representation of the control this.control.setAttribute("aria-valuenow", this.sliceCount); const sliceModifier = this.sliceCount === 1 ? "slice" : "slices"; this.control.setAttribute("aria-valuetext", `${this.sliceCount} ${sliceModifier}`); } }
-
7:52 - SSML examples
<speak> Breathe in <break time="3s"/> and breathe out. </speak> <speak> <phoneme alphabet="ipa" ph="təˈmeɪtoʊ">tomato</phoneme> <phoneme alphabet="ipa" ph="təˈmɑːtəʊ">tomato</phoneme> </speak> <speak> <prosody pitch="-2st" rate="slow" volume="loud"> Hello world! </prosody> </speak>
-
8:45 - "Read question" button HTML markup
<button id="read-question-btn"> Read question<span aria-hidden="true">🔊</span> </button>
-
8:57 - wrapWithSSML JavaScript function
function wrapWithSSML(phrase, locale) { return ` <break time=“100ms"/> <prosody rate=“80%"> <lang xml:lang="${locale}"> ${phrase} </lang> </prosody> `; }
-
9:24 - Read question button click event listener
const readQuestionButton = document.getElementById("read-question-btn"); readQuestionButton.addEventListener("click", () => { const ssml = ` <speak> How do you say ${wrapWithSSML("the water", "en-US")} in Spanish? ${wrapWithSSML("El agua", "es-MX")} ${wrapWithSSML("La abuela", "es-MX")} ${wrapWithSSML("La abeja", "es-MX")} ${wrapWithSSML("El árbol", "es-MX")} </speak> `; const utterance = new SpeechSynthesisUtterance(ssml); window.speechSynthesis.speak(utterance); });
-
11:33 - Show score dialog HTML markup
<dialog id="show-score-modal"> <form method="dialog"> You got all six questions correct. Great work! <button type="submit">Close</button> </form> </dialog>
-
11:51 - JavaScript to open show score dialog
const showScoreButton = document.getElementById("show-score-btn"); showScoreButton.addEventListener("click", () => { document .getElementById("show-score-modal") .showModal(); });
-
13:23 - Show score dialog with autofocus and aria-labelledby attribute
<dialog id="show-score-modal" aria-labelledby="modal-content"> <form method="dialog"> <span id="modal-content"> You got all six questions correct. Great work! </span> <button type="submit" autofocus>Close</button> </form> </dialog>
-
-
特定のトピックをお探しの場合は、上にトピックを入力すると、関連するトピックにすばやく移動できます。
クエリの送信中にエラーが発生しました。インターネット接続を確認して、もう一度お試しください。