mcpField
P
pixijs-accessibility

pixijs-accessibility

github.com/pixijsデザイン・UI3585.6k 回インストール4 週間前に更新
リポジトリ

pixijs-accessibility について

PixiJSのAccessibilitySystemを使い、キャンバスコンテンツにスクリーンリーダーとキーボードの対応を加えるスキルです。アクセシブルなラベル、タブ順序、操作の発火、実行時設定を説明します。

主な機能

  1. 01コンテナをスクリーンリーダーに公開
  2. 02アクセシブルなタイトルとヒントの設定
  3. 03キーボードのタブ順序の制御
  4. 04アクセシブルな操作イベントの送出
  5. 05アクセシビリティ有効化の設定

活用シーン

  1. 01キャンバス上のボタンをキーボード対応にする
  2. 02シーン要素にスクリーンリーダー用ラベルを追加
  3. 03アクセシビリティオーバーレイのテスト

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/pixijs/pixijs-skills --skill pixijs-accessibility

インストール後、Claude Code で/pixijs-accessibilityを入力して読み込まれたか確認します。

詳細

PixiJS の AccessibilitySystem を使用して、スクリーンリーダーとキーボードナビゲーションを有効にします。このシステムは、支援技術がアクセス可能なコンテナーを検出して操作できるように、コンテナー上に配置された不可視のシャドウ DOM オーバーレイを作成します。

クイックスタート

const button = new Sprite(await Assets.load("button.png"));
button.accessible = true;
button.accessibleTitle = "Play game";
button.accessibleHint = "Starts a new game session";
button.eventMode = "static";
button.tabIndex = 0;
app.stage.addChild(button);

app.renderer.accessibility.setAccessibilityEnabled(true);

button.on("pointertap", () => startGame());

関連スキル: pixijs-events(ポインター/タップハンドラー)、pixijs-scene-dom-container(キャンバス上の HTML 要素)、pixijs-application(初期化オプション)。

要点:

  • デフォルトでは、ユーザーが Tab キーを押した後にのみシステムが有効になります。すぐに有効にするには、Application の初期化で enabledByDefault: true を設定します。
  • モバイルでは、システムは非表示のタッチフックを作成します。スクリーンリーダーでフォーカスすると、セッション全体でアクセシビリティが有効になります。
  • AccessibilitySystem にはメインスレッドが必要です。Web Worker では利用できません。

基本パターン

コンテナーのアクセシビリティプロパティ
import { Container, Sprite } from "pixi.js";

const container = new Container();
container.accessible = true;
container.accessibleTitle = "Navigation menu";
container.accessibleHint = "Contains links to other pages";
container.eventMode = "static"; // required for custom tabIndex to apply
container.tabIndex = 0;
container.accessibleType = "div"; // defaults to 'button'

const sprite = new Sprite();
sprite.accessible = true;
sprite.accessibleTitle = "Close dialog";
sprite.accessibleText = "X"; // text content of the shadow div
sprite.eventMode = "static";
sprite.tabIndex = 1;

すべての Container で使用できるプロパティ:

  • accessible(boolean)- アクセシブルなオーバーレイ div を有効にします
  • accessibleTitle(string)- シャドウ div の title 属性を設定します
  • accessibleHint(string)- aria-label 属性を設定します
  • accessibleText(string)- シャドウ div の内部テキストコンテンツを設定します
  • accessibleType(string)- シャドウ要素の HTML タグです。デフォルトは 'button' です
  • tabIndex(number)- キーボードナビゲーションのタブ順序です(interactive が true、または eventMode が 'static' か 'dynamic' の場合にのみ適用されます)
  • accessibleChildren(boolean、デフォルトは true)- false の場合、子コンテナーがアクセシブルになるのを防ぎます
  • accessiblePointerEvents(string)- シャドウ div の CSS pointer-events 値です
カスタムのタブ順序

各アクセシブルコンテナーに tabIndex を設定して、支援技術がたどる順序を制御します。数値が大きいものほど後になります。同じ数値の場合は、シーングラフの順序に従います。

menuButton.accessible = true;
menuButton.eventMode = "static";
menuButton.tabIndex = 1;

playButton.accessible = true;
playButton.eventMode = "static";
playButton.tabIndex = 2;

settingsButton.accessible = true;
settingsButton.eventMode = "static";
settingsButton.tabIndex = 3;

tabIndex がシャドウ div に渡されるのは、コンテナーが interactive(eventMode が 'static' または 'dynamic')の場合のみです。そうでない場合、システムは div の tabIndex を 0 に戻すため、設定した順序は無視されます。

プログラムによる制御
import { Application } from "pixi.js";

const app = new Application();
await app.init({ width: 800, height: 600 });

// Enable accessibility at runtime
app.renderer.accessibility.setAccessibilityEnabled(true);

// Check current state
console.log(app.renderer.accessibility.isActive);
console.log(app.renderer.accessibility.isMobileAccessibility);

// Full init options:
await app.init({
  accessibilityOptions: {
    enabledByDefault: true, // activate immediately (default: false)
    debug: true, // makes overlay divs visible (default: false)
    activateOnTab: true, // Tab key activates system (default: true)
    deactivateOnMouseMove: false, // stay active when mouse moves (default: true)
  },
});

Application を作成する前に、静的なデフォルト値を使ってシステムを設定することもできます。

import { AccessibilitySystem, Application } from "pixi.js";

AccessibilitySystem.defaultOptions.enabledByDefault = true;
AccessibilitySystem.defaultOptions.deactivateOnMouseMove = false;

const app = new Application();
await app.init();
アクセシブルなインタラクションの処理
import { Sprite } from "pixi.js";

const button = new Sprite();
button.eventMode = "static";
button.accessible = true;
button.accessibleTitle = "Submit form";
button.tabIndex = 0;

// Screen readers trigger click/tap events through the shadow DOM element
button.on("pointertap", () => {
  submitForm();
});

アクセシビリティが有効なときに、ユーザーがシャドウ div を操作すると(Enter/Space キー、またはスクリーンリーダーの操作によって)、システムは対応するコンテナーに click、pointertap、tap の FederatedEvents をディスパッチします。シャドウ div がフォーカスされると mouseover がディスパッチされ、フォーカスが外れると mouseout がディスパッチされます。キーボードとポインターの両方を完全にサポートするには、eventMode と accessible の両方を設定してください。

よくある間違い

[MEDIUM] Tab キーを押さなくてもアクセシビリティが有効になると考える

AccessibilitySystem は、ユーザーが Tab キーを押すまで(モバイルの場合はタッチフックにフォーカスするまで)、DOM オーバーレイを作成しません。アプリケーションでアクセシビリティをすぐに有効にする必要がある場合:

const app = new Application();
await app.init({
  accessibilityOptions: {
    enabledByDefault: true,
  },
});

または、実行時に:

app.renderer.accessibility.setAccessibilityEnabled(true);

いずれかを設定しないと、自動アクセシビリティテストツールはオーバーレイ要素を検出できません。

[MEDIUM] accessibleTitle を設定せずに accessible を設定する

誤り:

const sprite = new Sprite();
sprite.accessible = true;
// no title or hint set

正しい例:

const sprite = new Sprite();
sprite.accessible = true;
sprite.accessibleTitle = "Play button";
sprite.accessibleHint = "Click to start the game";

accessible = true でも accessibleTitle または accessibleHint が設定されていないコンテナーには、"container {tabIndex}" というフォールバックタイトルが設定されます。スクリーンリーダーは、役立つコンテキストのないこの汎用ラベルを読み上げます。必ず accessibleTitle を設定してください。

[MEDIUM] マウスを動かすとアクセシビリティが無効になる

デフォルトでは、deactivateOnMouseMove は true です。Tab キーで有効にした後にマウスを動かすと、オーバーレイは無効になります。これは仕様です(キーボードのみを使用するユーザーはマウスを使わないと想定しています)が、マウスを使ったテストでは不便です。

await app.init({
  accessibilityOptions: {
    deactivateOnMouseMove: false,
  },
});
[MEDIUM] カスタムビルドでアクセシビリティ拡張をインポートしていない

カスタムビルドで skipExtensionImports: true を使用する場合、アクセシビリティ拡張は自動的に登録されません。明示的にインポートする必要があります:

import "pixi.js/accessibility";
import { Application } from "pixi.js";

const app = new Application();
await app.init({ skipExtensionImports: true });

このインポートがないと、app.renderer.accessibility は undefined になり、シャドウ DOM レイヤーも作成されません。

API Reference

コメント