WCAG 達成基準 · Level AAA
WCAG 2.5.6: 同時入力メカニズム
WCAG 2.5.6 は、プラットフォーム上で複数の入力手段が利用可能な場合に、ウェブコンテンツがユーザーを単一の入力モダリティに制限しないことを求めており、人々がタッチ、キーボード、マウス、音声などの入力方法を自由に切り替えても機能へのアクセスを失わないようにすることを保証している。
- Level AAA
このルールの意味
\nWCAG 2.5.6 — Concurrent Input Mechanisms(同時入力メカニズム)は、WCAG 2.2 におけるレベル AAA の達成基準です。その中核となる要件はシンプルで、ウェブコンテンツは、ユーザーが複数の入力メカニズムを同時に、または入れ替えて使用する能力を制限したり妨げたりしてはならないというものです。実務的には、ウェブページやアプリケーションは、ユーザーが現在どの入力デバイスを使っているかをプログラム的に検出し、その単一のモダリティにユーザーを固定して、他の利用可能な入力方法へのアクセスを拒否してはならない、という意味になります。
\n現代のデバイスは、物理キーボード、マウスやトラックパッド、タッチスクリーン、スタイラス、スイッチコントロール、音声入力、視線追跡など、豊富な入力メカニズムをサポートしています。多くのユーザーは、これらのうち複数を同時に利用しています。たとえば、タッチスクリーン付きのノート PC ユーザーは、タッチパッドと指によるタッチインターフェイスを流れるように切り替えるかもしれません。パワーユーザーは、フォームをキーボードで操作しながら、スクロールにはマウスを使うことがあります。運動障害のある人は、ヘッドポインタとスイッチデバイスの組み合わせを使うかもしれません。この達成基準は、これらすべてのワークフローを保護します。
\n失敗となるのは、ウェブサイトが JavaScript を使って使用中の入力タイプを検出し、他の入力タイプの機能を削除または無効化する場合です。たとえば、サイトがタッチイベントを検出した後にキーボードフォーカスインジケータを削除したり、キーボードナビゲーションを無効にしたりする場合、これは直接的な違反です。同様に、キーボード使用を検出した後にポインタ入力をブロックしたり、プラットフォーム API を使って入力を人工的に単一のモダリティに制限したりすることも、すべて失敗に該当します。
\n達成となるのは、ユーザーがインタラクションの任意の時点で、利用可能なあらゆる入力メカニズムを使って操作できる場合です。コンテンツは、ページの再読み込みやモード切り替え、あるいは入力タイプを再度有効にするための追加のユーザー操作を必要とすることなく、ユーザーがその時点で選択したどの入力メカニズムにも正しく応答しなければなりません。
\nこの達成基準には、WCAG で定義された公式の例外が 1 つ含まれています。制限が本質的に必要な場合、つまり特定の入力モダリティが本質的に要求される場合には許可されます。典型的な例は、手書き認識アプリケーションで、タッチまたはスタイラス入力こそが機能の要となっているケースです。別の例としては、特定のポインタ入力を必要とするデジタル署名の入力フィールドが挙げられます。これらのケースであっても、この例外は狭く解釈されるべきであり、著者は可能な限り、タスクを完了するための代替手段を提供すべきです。
\nこの達成基準は、デバイスが持たない入力メカニズムへのサポートを著者に追加することを求めるものではない点に注意が必要です。これは、デバイスやプラットフォームがすでにサポートしているメカニズムに対して課される制限を対象としています。デバイスにタッチスクリーンがない場合、制限すべきものは何もありません。
\n\nなぜ重要か
\n同時または交換可能な入力メカニズムを使用する自由は、単なる利便性の機能ではなく、複数の異なるユーザーグループに直接影響する重要なアクセシビリティ要件です。
\n運動障害のあるユーザーは、多くの場合、複数の入力メカニズムを組み合わせた支援技術に依存しています。手の可動域が限られている人は、画面上のキーボードと併せて sip-and-puff スイッチデバイスを使用するかもしれません。震えのある人は、最初はキーボードでページを操作し、キーボードショートカットがうまくいかないときにはマウスやタッチインターフェイスに切り替えることがあります。ウェブサイトがある入力タイプを検出して他の入力タイプを無効にすると、これらのユーザーはコンテンツや機能にまったくアクセスできなくなる可能性があります。
\n認知障害や学習障害のあるユーザーは、タスクごとに最も快適で自然に感じられる入力方法を選べることから大きな恩恵を受けることがよくあります。単一のモダリティを強制すると、その選択肢が奪われ、特にユーザーがデバイスの主要な入力方法に習熟していない場合には、不要な認知的負荷を生む可能性があります。
\n高齢者は、加齢に伴う運動上の課題を抱えていることがありますが、タッチとキーボードの両方をサポートするデバイスを利用するケースが増えています。細かな運動制御が一日の中で変動する中で、これらのメカニズムを切り替えられることは、ウェブを自立して継続的に利用するうえで重要です。
\nパワーユーザーやマルチモーダルなデバイスユーザー(Surface Pro や iPad Pro のユーザーなど)は、同じデバイス・同じセッション内で、キーボード、スタイラス、タッチインターフェイスを日常的に併用しています。タッチ入力を検出してキーボードショートカットを削除したり、その逆を行ったりするウェブサイトは、障害があると自認していない膨大なユーザーベースの体験を損なうことになります。
\n現実のシナリオを考えてみましょう。あるトルコの銀行のオンラインポータルは、顧客がタッチスクリーンタブレットを使用していることを検出すると、「モバイルモード」に切り替え、キーボードナビゲーションを無効にします。Bluetooth キーボードと併用してタブレットを使っている運動障害のある顧客は、フォームフィールドを Tab キーで移動したり、矢印キーでメニューを操作したり、キーボードショートカットを使ったりできなくなります。その人は銀行の手続きを自力で完了できません。これはアクセシビリティ上の失敗であるだけでなく、トルコのアクセシビリティ規制の下で法的リスクにもなり得ます。
\nユーザビリティと SEO の観点からも、同時入力メカニズムを尊重することは、Core Web Vitals のスコア向上、直帰率の低下、多様なデバイスカテゴリにおけるユーザー満足度の向上と相関しており、これらは検索エンジンが評価するシグナルです。
\n\n関連する Axe-core のルール
\nWCAG 2.5.6 は手動テストを必要とします。この達成基準のすべての違反を確実に検出できる自動化された axe-core のルールは存在しません。その理由は本質的なものです。自動ツールは静的な DOM と CSS を検査でき、特定の JavaScript パターンを検出することもできますが、実際のユーザーセッション中に、さまざまな入力モダリティに応じてイベントリスナーがどのように動作するかというランタイムの挙動を完全に観察することはできません。入力メカニズムを制限するという判断は、多くの場合、特定のイベントに応じてのみ実行されるアプリケーションロジックの中にコード化されており、静的解析だけでは不十分なのです。
\n- \n
- 2.5.6 専用の自動 axe-core ルールは存在しません。axe-core には、同時入力メカニズムの制限を特にチェックするルールは含まれていません。なぜなら、違反は HTML や ARIA の構造的な問題ではなく、動的な JavaScript の挙動として現れるからです。ページはすべての自動 axe チェックに合格していても、イベントハンドラが実行時に入力モダリティをプログラム的に削除または無効化する場合、2.5.6 に違反している可能性があります。 \n
- ポインタイベントとタッチイベントの検出: axe-core 自体は制限そのものを検出できませんが、手動の監査者は、
touchstartやpointerdownイベントを監視し、その後 DOM を変更したり、フォーカス管理を削除したり、キーボードの挙動を変えるフラグを設定したりする JavaScript を探すべきです。同様に、CSS クラスの変更をトリガーしてタッチターゲットを隠すkeydownリスナーも、手動で精査すべき警告サインです。 \n - 自動化が不十分な理由: 自動スキャナは、ある時点のドキュメントを解析します。入力メカニズムの制限は条件付きであり、特定の入力イベントが発火した後にのみ有効になります。ユーザーインタラクションの前にスキャナを実行しても、
touchstartハンドラが後でdocument.querySelectorAll('[tabindex]').forEach(el => el.setAttribute('tabindex', '-1'))を呼び出し、事実上キーボードナビゲーションを破壊することは見えません。両方の入力モダリティを順番に試す人間のテスターだけが、この失敗を発見できます。 \n
テスト方法
\n- \n
- 自動ベースラインスキャン: ページに対して axe DevTools や Lighthouse を実行し、ベースラインを確立するとともに、同時に発生している他の問題を検出します。どちらのツールにも 2.5.6 専用のルールはありませんが、axe DevTools のベストプラクティスチェックは、入力制限の兆候となるキーボードトラップやフォーカス管理の問題を検出する場合があります。以下の手動チェックと併せて、検出された失敗を修正対象として記録します。 \n
- JavaScript ソースとイベントリスナーの検査: Chrome DevTools を開き、Elements パネルに移動し、Event Listeners ペインを使って、
touchstart、pointerdown、pointermove、MSPointerDownリスナーが document や body にアタッチされているかどうかを確認します。Console では、ページの JavaScript ソース内をontouchstart in window、navigator.maxTouchPoints、'pointer' in navigatorのようなパターンと、それに組み合わされた DOM 変更を検索します。これらは、入力モダリティを検出し、機能を制限するためによく使われる手法です。 \n - マルチモダリティインタラクションテスト(キーボード + タッチ): Surface、キーボード付き iPad、タッチスクリーン搭載ノート PC など、タッチとキーボード入力の両方をサポートするデバイスで、まずキーボードのみ(Tab、Shift+Tab、Enter、Space、矢印キー)でページを操作します。到達可能で機能しているインタラクティブ要素を確認します。その後、ページを再読み込みせずにタッチ操作に切り替え、リンク、ボタン、フォームコントロールをタップします。キーボードで利用可能だったすべての機能がタッチでも利用可能であり、その逆も同様であることを確認します。切り替え後に到達不能または機能しなくなる要素があれば記録します。 \n
- スクリーンリーダーと組み合わせた入力テスト: NVDA と Firefox を使用して、キーボードでページを操作し、スクリーンリーダーモードを有効にします。その後、(利用可能であれば)タッチスクリーンを使って同じ要素を操作しようとします。スクリーンリーダーとページが、両方の入力に正しく応答することを確認します。iPad 上の Safari で VoiceOver を使う場合も同様に、タッチジェスチャーとペアリングした Bluetooth キーボードの両方を使って繰り返します。Chrome 上の JAWS では、キーボードとマウスの切り替えによってフォーカス管理が壊れたり、インタラクティブ要素が操作不能になったりしないことを確認します。 \n
- モダリティ固定パターンのコードレビュー: ページで使用している JavaScript ライブラリやフレームワークを手動でレビューし、組み込みのモダリティ検出がないか確認します。特に古いモバイルファーストの UI ライブラリの中には、タッチが検出されたデバイスでマウスやキーボードイベントを無効にするコードを含むものがあります。ライブラリのドキュメントやソースを確認し、そのような挙動が上書きまたは無効化されていることを確かめます。 \n
- 動的インタラクション後の再テスト: モーダルのオープン、シングルページアプリのルート遷移、フォーム送信など、DOM に大きな変更を引き起こす操作を行い、その都度マルチモダリティテストを再実行します。制限が特定のアプリケーション状態でのみ導入されることもあります。 \n
修正方法
\nタッチを検出してキーボードナビゲーションを無効化する — 誤り
\n<!-- JavaScript がタッチを検出してすべての tabindex 値を削除し、\n 入力モードを切り替えるユーザーのキーボードナビゲーションを壊してしまう -->\n<script>\n window.addEventListener('touchstart', function() {\n document.querySelectorAll('a, button, input, [tabindex]').forEach(function(el) {\n el.setAttribute('tabindex', '-1');\n });\n }, { once: true });\n</script>\nタッチを検出してキーボードナビゲーションを無効化する — 正しい例
\n<!-- タッチ検出に基づいてキーボードアクセシビリティを制限しない。\n 両方の入力モダリティが同時に機能するようにする。\n 見た目のためにフォーカススタイルを調整する必要がある場合は、\n tabindex を削除するのではなく :focus-visible CSS 疑似クラスを使用する。 -->\n<style>\n /* キーボードナビゲーション時のみフォーカスリングを表示し、\n マウスクリック時には表示しない。ただしキーボードアクセス自体は維持する */\n :focus:not(:focus-visible) {\n outline: none;\n }\n :focus-visible {\n outline: 3px solid #005fcc;\n outline-offset: 2px;\n }\n</style>\n<!-- JavaScript によるモダリティ検出は不要 -->\n\nポインタイベントでキーボードイベントを抑制する — 誤り
\n<!-- カスタムスライダーがポインタ入力を受け取ると、\n キーボードの矢印キーへの応答をやめてしまい、\n ユーザーをポインタのみの操作に固定してしまう -->\n<div id='slider' role='slider' aria-valuenow='50' aria-valuemin='0'\n aria-valuemax='100' tabindex='0'></div>\n<script>\n var slider = document.getElementById('slider');\n var pointerUsed = false;\n slider.addEventListener('pointerdown', function() {\n pointerUsed = true;\n });\n slider.addEventListener('keydown', function(e) {\n if (pointerUsed) return; // ポインタ操作後はキーボードを無効化\n if (e.key === 'ArrowRight') { /* increment */ }\n if (e.key === 'ArrowLeft') { /* decrement */ }\n });\n</script>\nポインタイベントでキーボードイベントを抑制する — 正しい例
\n<!-- ポインタとキーボードの両方のインタラクションを独立して処理する。\n 一方を使用した後に他方を無効にするフラグは設定しない。 -->\n<div id='slider' role='slider' aria-valuenow='50' aria-valuemin='0'\n aria-valuemax='100' tabindex='0'></div>\n<script>\n var slider = document.getElementById('slider');\n var value = 50;\n\n function updateSlider(newValue) {\n value = Math.max(0, Math.min(100, newValue));\n slider.setAttribute('aria-valuenow', value);\n }\n\n // ポインタハンドラ — 常に有効\n slider.addEventListener('pointermove', function(e) {\n if (e.buttons === 1) {\n // ポインタ位置から新しい値を計算\n }\n });\n\n // キーボードハンドラ — 常に有効で、ポインタ使用によって無効化されない\n slider.addEventListener('keydown', function(e) {\n if (e.key === 'ArrowRight') updateSlider(value + 1);\n if (e.key === 'ArrowLeft') updateSlider(value - 1);\n });\n</script>\n\nモバイルフレームワークが自動的にマウスイベントを無効化する — 誤り
\n\n(Content truncated due to token limit — please retry this article.)
