WCAG 達成基準 · Level A

WCAG 2.5.4: 動きによる起動

WCAG 2.5.4 では、デバイスやユーザーの動き(振る、傾けるなど)によって起動されるあらゆる機能は、従来型のユーザーインターフェイスコンポーネントを通じても操作できなければならず、さらにユーザーは誤作動を防ぐためにモーションアクチュエーションを無効にできなければならないと定められています。

このルールの意味

WCAG 2.5.4 — Motion Actuation(動きによる操作)は、現代のウェブアプリケーションでますます一般的になっている特定のシナリオ、つまりスマートフォンを振る、デバイスを傾ける、カメラの前でジェスチャーを行うといった物理的なデバイスの動きによって機能がトリガーされるケースを扱います。この達成基準は、適合のために両方満たさなければならない2つの並行する要件を定めています。

第一に、デバイスの動きやユーザーの動きによって操作できるあらゆる機能は、ユーザーインターフェイスコンポーネントを通じても操作できなければなりません。つまり、ボタン、リンク、フォームコントロールなど、動きに依存しない類似のインタラクティブ要素です。これにより、身体的な動きのジェスチャーを行えない、あるいは安定して行えない人々が、その機能へのアクセスから完全に排除されないようにします。

第二に、ユーザーは動きへの反応を無効化できなければなりません。そうすることで、偶発的または不随意の動きによって意図しないアクションがトリガーされないようにします。これは、振戦やその他の運動障害により意図しないデバイスの動きが生じるユーザーが、予期しないアプリケーションの挙動によって常に妨げられることから保護します。

この達成基準は2つの異なるタイプの動きに適用されます。1つはデバイスの動きで、スマートフォンやタブレットに内蔵された加速度センサーやジャイロスコープ(DeviceMotionEventDeviceOrientationEvent のようなAPIを通じてアクセス)などのセンサーによって検出されます。もう1つはユーザーの動きで、デバイス自体ではなく身体の動きやジェスチャーを追跡するカメラやその他の入力センサーによって検出されます。

適合している実装では、すべての動きによってトリガーされる機能が標準的なUIコントロール(ボタン、リンク、または同等のもの)を通じても提供され、かつユーザーが望めば動きの検出をオフにできるようになっています。不適合な実装は、機能へのアクセスを動きのみに依存させて代替のUIコントロールを提供していない場合、または代替手段はあるものの、不随意の動きによって問題が生じないように動きのトリガーを無効化する方法を提供していない場合です。

WCAG 2.5.4は2つの重要な例外を定義しています。動きによる操作は、その動きが機能にとって本質的であり、それを無効化すると活動自体が根本的に変わってしまう場合には適用除外となります。たとえば、歩数計測がコアの目的であるフィットネスアプリケーションや、傾きのメカニクスを中心に設計されたゲームなどです。2つ目の例外は、動きがサポートされたアクセシビリティインターフェイスを通じて機能を操作するために使われている場合に適用されます。これは、プラットフォーム自身のアクセシビリティ機能が、ユーザーが独立して制御できる形で動きのインタラクションを処理していることを意味します。

なぜ重要か

動きによる操作のバリアは、運動障害や移動に関する障害のある人々に不均衡に影響しますが、その影響は多くの開発者が当初想定するよりも広範です。誰がどのように影響を受けるのかを理解することで、チームはこの達成基準に適切な優先度を与えられます。

振戦のある人々—本態性振戦、パーキンソン病、多発性硬化症などを含む—は、手や腕の持続的または断続的な不随意運動を経験することがあります。スマートフォンを手に持つと、自然な振戦だけで「シェイクして取り消し」ダイアログ、リフレッシュアクション、その他の動きで起動する機能が繰り返し予期せずトリガーされてしまいます。世界保健機関は、世界で約13億人が何らかの重大な障害を抱えて生活していると推計しており、微細運動の制御に影響する状態は、あらゆる年齢層で最も一般的なものの一つです。

麻痺や四肢の差異がある人々は、車椅子やスタンドに取り付けたデバイスを使用したり、ヘッドポインタ、視線追跡、スイッチコントロールなどを使ってデバイスとやり取りしている場合があります。これらのユーザーはデバイスをまったく振ったり傾けたりできないことが多く、動きのみの機能は完全にアクセス不能になります。モバイルウェブアプリケーションでテキスト入力を取り消す唯一の方法がデバイスを振ることだけであれば、電話をマウントしている車椅子ユーザーはその機能にまったくアクセスできません。

高齢者もまた大きく影響を受けるグループです。握力の低下、関節炎、本態性振戦などの加齢に伴う状態は年齢とともにますます一般的になり、同時にデジタル利用が活発になっている人口の増加セグメントが、正確で意図的な動きのジェスチャーに苦労する可能性が高まります。

具体的な現実のシナリオを考えてみましょう。あるトルコのECサイトが、ユーザーがスマートフォンを振るとランダムな商品をおすすめとして表示する「シェイクしてシャッフル」機能を追加し、閲覧をより魅力的にしました。この機能は楽しく斬新ですが、シャッフルをトリガーするボタンの同等機能はなく、シェイク検出をオフにする方法もありません。そのサイトを訪れたパーキンソン病のユーザーは、自然な振戦がジェスチャーをトリガーするため、制御不能なシャッフルが絶えず発生します。ページがランダムな商品に飛び続けるため、落ち着いて閲覧することができません。このユーザーは実質的に通常のショッピング体験から締め出されており、トルコのアクセシビリティ規制の下では、これは単なるUXの問題ではなく、法令遵守上の不履行となります。

障害のある人々のアクセスにとどまらず、動きの機能を無効化したり代替手段を提供したりすることは、デバイスの動きが不安定な環境—公共交通機関、オフィス、あるいはユーザーが自由にデバイスを動かせないあらゆる状況—で利用するユーザーの体験も向上させます。

関連する axe-core のルール

WCAG 2.5.4は手動テストを必要とします。なぜなら、自動ツールは静的なHTMLとCSSの解析だけでは、動きに基づく機能の有無を確実に検出できないからです。動きによる操作は、JavaScriptのイベントリスナーや実行時の挙動に依存しており、自動スキャナはそれを完全には内省できません。以下では、自動化がなぜ不十分なのか、そして手動評価で何をカバーしなければならないのかを説明します。

  • 2.5.4に対する直接の axe-core 自動ルールは存在しません。axe-core や類似の自動エンジンは、DOM、ARIA属性、計算済みスタイルを検査することで動作します。これらは、ページが devicemotiondeviceorientation イベントリスナーを登録しているかどうかを観察できず、また動きでトリガーされる機能に対して同等のUIコントロールが存在するかどうかも判断できません。ページは、DOM上には何の痕跡もないまま、動きに基づくインタラクションを広範に持っている可能性があり、自動検出を根本的に信頼できないものにします。そのため axe-core は、この達成基準を自動検出を試みるのではなく、手動レビューが必要なものとしてフラグ付けします。自動検出を試みると、高い偽陰性率を生むからです。
  • JavaScript イベントリスナーの手動検査が必要です。テスターはブラウザの開発者ツールを使い、DeviceMotionEventDeviceOrientationEvent、Shape Detection API のようなカメラ/ビジョンAPIの登録を検索する必要があります。DevTools の Event Listeners パネルを使うと、これらのイベントが window や document オブジェクトにアタッチされているかどうかを確認できます。
  • 機能の同等性は自動化できません。仮にツールが動きのリスナーを検出できたとしても、インターフェイスの別の場所に同じ機能を提供するボタンやリンクが存在するかどうかを判断することはできません。機能の同等性を評価するには、アプリケーションの機能を理解し、動きでトリガーされるすべてのアクションに到達可能で操作可能なUIの代替手段があることを確認できる人間のテスターが必要です。
  • 無効化可能かどうかは自動化できません。ユーザーが動きへの反応をオフにできるかどうかを判断するには、アプリケーションの設定や環境設定と実際にやり取りする必要があります。これは、自動ツールが包括的に実行するよう設計されていない挙動テストです。

テスト方法

  1. 出発点としての自動スキャン:ページで axe DevTools、Lighthouse、または Accsible アクセシビリティチェッカーを実行します。これらのツールは2.5.4の違反を自動的にはフラグ付けしませんが、関連する問題を表面化させる可能性があります。フラグ付けされた項目をメモし、その後手動ステップに進みます。自動フラグがないことは、そのページが2.5.4に適合していることを意味しません。
  2. 動きでトリガーされる機能の特定:Chrome DevTools を開き、Elements パネルに移動します。Sources タブと Ctrl+Shift+F によるグローバル検索を使って、ページの JavaScript ソースファイル内で devicemotiondeviceorientationacceleratgyroshake という文字列を検索します。見つかったすべてのインスタンスと関連する機能を記録します。
  3. UI の代替手段が存在するかの確認:前のステップで見つけた動きでトリガーされる各機能について、デバイスの動きを使わずに、キーボード操作とマウスクリックだけで同じアクションを実行できるか試みます。Tab、Enter、Space、矢印キーを使ってインターフェイスをナビゲートします。同じ結果を達成できる操作可能なUIコントロールが見つからない場合、その達成基準は不適合です。
  4. 動きを無効化できるかの確認:設定メニュー、環境設定パネル、アクセシビリティ設定、または動きの機能専用のトグルを探します。動きによる操作を無効化しようとします。そのようなコントロールが存在しない場合、または動きを無効化するとUIの代替手段も同時に無効化されてしまう場合、その達成基準は不適合です。
  5. 実機でのテスト:実際のスマートフォンやタブレットでページを読み込みます。デバイスを意図的に優しく動かし(小さく連続した動きで不随意の振戦をシミュレート)、機能が意図せずトリガーされるかどうかを観察します。その後、利用可能な設定で動きを無効化した後に同じテストを試みます。
  6. スクリーンリーダーとキーボードでのテスト:NVDA と Firefox、iOS の Safari と VoiceOver、または JAWS と Chrome を使用し、キーボードとスクリーンリーダーのコマンドだけでページをナビゲートします。動きによって到達可能なすべての機能が、スクリーンリーダーのナビゲーションでも到達可能であること、そして(存在する場合)動きを無効化するコントロール自体がキーボードでアクセス可能で適切にラベル付けされていることを確認します。
  7. ブラウザ DevTools によるデバイスシミュレーション:Chrome DevTools で Sensors パネル(More Tools > Sensors)を開き、デバイスの向きと加速度センサーのシミュレーションコントロールを使って、プログラム的に動きのイベントをトリガーします。これにより、物理デバイスを使わずにデスクトップ上で動きによる挙動をテストできます。

修正方法

代替手段のない「振ってリフレッシュ」— 不適切

<!-- Motion listener attached, but no UI button provided to refresh -->
<script>
  window.addEventListener('devicemotion', function(event) {
    var acceleration = event.accelerationIncludingGravity;
    if (Math.abs(acceleration.x) > 15 || Math.abs(acceleration.y) > 15) {
      refreshContent();
    }
  });
</script>
<div id='content'>...page content...</div>

代替手段のある「振ってリフレッシュ」— 適切

<!-- Motion alternative: a visible button provides the same refresh action.
     A settings toggle lets users disable the motion trigger entirely. -->
<div id='motion-controls'>
  <button type='button' id='refresh-btn' onclick='refreshContent()'>
    Refresh Content
  </button>
  <label>
    <input type='checkbox' id='disable-motion' onchange='toggleMotion(this.checked)' />
    Disable shake-to-refresh
  </label>
</div>
<div id='content'>...page content...</div>
<script>
  var motionEnabled = true;
  function toggleMotion(disabled) {
    motionEnabled = !disabled;
  }
  window.addEventListener('devicemotion', function(event) {
    if (!motionEnabled) return;
    var acceleration = event.accelerationIncludingGravity;
    if (Math.abs(acceleration.x) > 15 || Math.abs(acceleration.y) > 15) {
      refreshContent();
    }
  });
  function refreshContent() {
    // fetch and update content
  }
</script>

無効化オプションのない「傾けてスクロールするカルーセル」— 不適切

<!-- Carousel advances on device tilt; no way to turn this off -->
<div id='carousel'>
  <div class='slide'>Slide 1</div>
  <div class='slide'>Slide 2</div>
  <div class='slide'>Slide 3</div>
</div>
<script>
  window.addEventListener('deviceorientation', function(event) {
    if (event.gamma > 30) advanceCarousel();
    if (event.gamma < -30) retreatCarousel();
  });
</script>

無効化オプションのある「傾けてスクロールするカルーセル」— 適切

<!-- Previous/Next buttons provide UI alternatives.
     A settings checkbox lets users opt out of tilt control.
     The carousel is also keyboard accessible via arrow keys. -->
<div id='carousel-wrapper'>
  <button type='button' aria-label='Previous slide' onclick='retreatCarousel()'>&laquo;</button>
  <div id='carousel' role='region' aria-label='Image carousel' aria-live='polite'>
    <div class='slide' aria-hidden='false'>Slide 1</div>
    <div class='slide' aria-hidden='true'>Slide 2</div>
    <div class='slide' aria-hidden='true'>Slide 3</div>
  </div>
  <button type='button' aria-label='Next slide' onclick='advanceCarousel()'>&raquo;</button>
</div>
<label>
  <input type='checkbox' id='disable-tilt' onchange='tiltEnabled = !this.checked' />
  Disable tilt navigation
</label>
<script>
  var tiltEnabled = true;
  window.addEventListener('deviceorientation', function(event) {
    if (!tiltEnabled) return;
    if (event.gamma > 30) advanceCarousel();
    if (event.gamma < -30) retreatCarousel();
  });
</script>

代替手段のないカメラジェスチャー機能 — 不適切

<!-- User waves hand in front of camera to dismiss a modal;
     no button or keyboard method exists to dismiss it otherwise -->
<div id='modal' role='dialog' aria-modal='true' aria-label='Notification'>
  <p>Wave your hand to dismiss this message.</p>
</div>
<script>
  startCameraGestureDetection(function onWave() {
    document.getElementById('modal').hidden = true;
  });
</script>

代替手段のあるカメラジェスチャー機能 — 適切

<!-- A clearly labeled close button provides the UI alternative.
     The modal is fully keyboard operable and focus is managed correctly. -->
<div id='modal' role='dialog' aria-modal='true' aria-labelledby='modal-title'>
  <h2 id='modal-title'>Notification</h2>
  <p>Wave your hand or press the button below to dismiss this message.</p>
  <button type='button' id='dismiss-btn' onclick='dismissModal()'>Dismiss</button>
</div>
<script>
  function dismissModal() {
    document.getElementById('modal').hidden = true;
    // return focus to triggering element
  }
  startCameraGestureDetection(dismissModal);
  // Allow Escape key to also dismiss
  document.addEventListener('keydown', function(e) {
    if (e.key === 'Escape') dismissModal();
  });
</script>

よくある間違い

  • UI の代替ボタンは提供しているが、動きを無効化するトグルを忘れている:多くの開発者はボタンの同等機能を追加しますが、動きのリスナーをオフにする方法を実装しません。その結果、機能自体は技術的には別の手段で操作可能であっても、振戦のあるユーザーは依然として望まない起動を経験し続けます。
  • 動き無効化オプションをハンバーガーメニューや深い設定ページの中に隠してしまう:動きを無効化するコントロール自体が簡単に到達できる必要があります。振戦のあるユーザーが、無効化するために5階層もメニューをたどる前に「振ってリフレッシュ」が繰り返しトリガーされてしまうようであれば、その無効化オプションは実質的にアクセス可能とは言えません。
  • OS レベルの「動きを減らす」設定で 2.5.4 を満たしていると想定してしまう:prefers-reduced-motion メディアクエリやOSのアクセシビリティ設定は、アニメーションや前庭(平衡感覚)に関する懸念に対処するものですが、ウェブアプリケーション内のデバイス動きイベントリスナーを自動的に無効化するものではありません。これらは自分のコードの中で処理する必要があります。
  • 動きの閾値を低く設定しすぎる:DeviceMotionEvent の加速度値に非常に敏感な閾値を使うと、軽微な不随意の振戦でも閾値を超えてしまいます。閾値は、意図的で大きな動きを必要とするように設定すべきであり、それでもなお無効化オプションは必須です。
  • window にグローバルに動きのリスナーを登録し、決して削除しない:removeEventListener を使ってリスナーを削除するコードパスを提供せずにリスナーをアタッチすると、無効化トグルは条件付きで挙動を抑制できるだけになります。トグル自体が失敗したりページの再読み込みでリセットされたりすると、動きは有効なままです。
  • 動きを無効化するチェックボックスをアクセシブルにしていない:無効化トグルを、適切な <input type='checkbox'> や ARIA で拡張されたコントロールではなく、クリックリスナー付きのスタイルされた <div><span> として実装すると、キーボードやスクリーンリーダーのユーザーは、本来彼らを助けるためのコントロールに到達したり操作したりできません。
  • ユーザーの動きに関する設定をセッション間で保持しない:ユーザーが動きによる操作を無効化しても、その設定が(localStorage やユーザーアカウント設定などで)保存されない場合、訪問のたびに再度無効化しなければならず、最も影響を受けるユーザーに繰り返し負担をかけることになります。
  • 本質的機能の例外を広く適用しすぎる:「本質的」例外は範囲が狭いものです。シェイクしてシャッフルする商品ギャラリーは本質的ではありません。シャッフル機能はショッピングサイトのコア機能ではないからです。実装作業を避けるために、この例外を誤って適用してしまうチームもあります。
  • 実際の物理デバイスと実際の動きでテストしていない:デスクトップのシミュレーションツールや自動スキャンだけに頼ると、ユーザーの自然な振戦がある場合に機能がどのように振る舞うかを含め、現実世界での動きの感度に関する問題は、ユーザーから報告されるまで決して発見されません。
  • サードパーティ SDK やアナリティクスライブラリによって追加された動きの機能も適合しなければならないことを忘れている:サードパーティのチャットウィジェット、ゲーミフィケーションSDK、A/Bテストツールに埋め込まれた動きのリスナーも、ページの適合責任の一部です。サードパーティスクリプトが代替手段を提供せずに devicemotion リスナーを登録している場合、そのページは2.5.4に不適合となります。

トルコのアクセシビリティ規制との関係

トルコの大統領通達第 2025/10 号は、2025年6月21日に官報(第32933号)で公布され、WCAG 2.2 に整合した必須のウェブアクセシビリティ要件を定めています。WCAG 2.5.4 Motion Actuation はレベルAの達成基準であり、この通達の下で最も優先度の高い必須適合レベルに位置付けられています。

この通達は、公的機関と民間部門の幅広い主体を対象としています。すべての中央および地方政府機関、省庁、公的機関を含む公的機関は、通達の公布から1年以内にレベルAの完全な適合を達成しなければなりません。対象となるカテゴリーの民間部門の主体は、同じ基準を2年以内に達成しなければなりません。対象となる民間部門のカテゴリーには、ECプラットフォームおよびマーケットプレイス、銀行および金融機関、病院および民間医療提供者、20万件以上の加入者を持つ通信会社、認可を受けた旅行代理店、民間輸送会社、国民教育省(MoNE)の認可の下で運営される私立学校が含まれます。

トルコのデジタルサービスにおいて動きによる操作が特に重要なのは、トルコではモバイルインターネット利用が非常に高く、ウェブトラフィックの大半がスマートフォンから来ているためです。そのため、モバイルファーストやモバイル専用のウェブアプリケーションは、対象となるすべてのセクターで極めて一般的です。UI の代替手段や無効化コントロールを提供せずに、シェイクしてリフレッシュ、傾きによるナビゲーション、ジェスチャーベースのインタラクション、その他類似の動きの機能を実装しているトルコのECサイト、バンキングアプリケーション、政府ポータルは、大統領通達 2025/10 の下で必須のレベルA要件に直接違反していることになります。

適合ロードマップを準備している対象主体にとって、動きによる操作は、より広範なモバイルアクセシビリティ監査の一部として評価されるべきです。自動ツールでは2.5.4の違反を検出できないため、組織は適合検証プロセスの一環として、資格を持つアクセシビリティ専門家による手動テストを含める必要があります。この通達には、公布前に実装された機能に対する猶予期間はなく、適合達成のためのタイムラインのみが定められているため、現在対象サイトで展開されている動きに基づく機能は、適用される期限内に是正されなければなりません。

通達の要件に従わない主体は、行政制裁に直面する可能性があり、自らのセクターの所管監督当局による執行の対象となります。規制上のリスクを超えて、トラフィックの多いトルコのモバイルサイトで2.5.4に適合していないことは、運動障害や振戦がある、あるいは支援技術を使用する何百万人ものユーザーにとって、実際のユーザビリティの失敗を意味します。こうした人々は、WCAG 2.2 レベルAをベースライン標準として採用したこの通達によって、そのニーズが明示的に認識され保護されている人口なのです。