pixijs-accessibility について
PixiJSのAccessibilitySystemを使い、キャンバスコンテンツにスクリーンリーダーとキーボードの対応を加えるスキルです。アクセシブルなラベル、タブ順序、操作の発火、実行時設定を説明します。
主な機能
- 01コンテナをスクリーンリーダーに公開
- 02アクセシブルなタイトルとヒントの設定
- 03キーボードのタブ順序の制御
- 04アクセシブルな操作イベントの送出
- 05アクセシビリティ有効化の設定
活用シーン
- 01キャンバス上のボタンをキーボード対応にする
- 02シーン要素にスクリーンリーダー用ラベルを追加
- 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 の CSSpointer-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 レイヤーも作成されません。