مرکزی مواد پر جائیں
友田 陽大
Frontend
React
Next.js
フロントエンド
アクセシビリティ
TypeScript
アーキテクチャ設計

Web アクセシビリティ実装ガイド【2026年版】— React / Next.js で WCAG 2.2 に準拠する実践テクニック

React / Next.js で WCAG 2.2(AA)に準拠するアクセシビリティ実装の完全ガイド。セマンティック HTML、キーボード操作、フォーカス管理、ARIA の正しい使い方、フォーム、コントラスト、prefers-reduced-motion、WCAG 2.2 の新基準、axe による自動テストまで実コードで解説します。

Published
Reading time
11 min read
Author
友田 陽大
شیئر کریں

アクセシビリティは「品質の総合点」が現れる場所です。雑なコンポーネント設計、状態管理の漏れ、フォーカスの放置——すべてが a11y の欠陥として表面化します。逆に言えば、a11y を担保できるチームは、コード品質そのものが高い。


1. なぜ今アクセシビリティなのか(ビジネスの観点)

技術論の前に、発注者にとっての価値を整理します。

  • 対象ユーザーの拡大。 何らかの支援を必要とする人は人口の相当割合に上ります。a11y はそのまま到達可能なユーザー数の拡大です。
  • 法令・調達要件。 公共・大企業の調達では WCAG 準拠が要件化されることが増えています。準拠していないと「そもそも候補に入れない」ことがあります。
  • SEO との相乗効果。 適切な見出し構造、代替テキスト、セマンティックなマークアップは、検索エンジンとスクリーンリーダーの双方に効きます。a11y 改善は集客改善でもあります。
  • 品質の証明。 アクセシブルなプロダクトは、設計が丁寧であることの証拠になります。発注判断の信頼材料になります。

つまり a11y は「コスト」ではなく「到達範囲・コンプライアンス・SEO・信頼」への投資です。


2. 土台:WCAG 2.2 の 4 原則(POUR)

WCAG はすべて 4 つの原則に集約されます。これを頭に入れておくと、個別テクニックが「なぜ必要か」で理解できます。

原則意味代表例
Perceivable(知覚可能)情報が知覚できる画像の代替テキスト、十分なコントラスト
Operable(操作可能)UI を操作できるキーボード操作、十分なターゲットサイズ
Understandable(理解可能)内容と操作が理解できる一貫したナビ、明確なエラー
Robust(堅牢)支援技術が解釈できる妥当な HTML、適切な name/role/value

レベルは A(最低限)< AA(標準)< AAA(最高)。実務の目標は AA です。


3. 最大のレバー:セマンティック HTML を使い切る

a11y の8割は、正しい要素を使うだけで達成できます。divspan でボタンやリンクを「作る」のをやめることが、最も費用対効果の高い改善です。

// ❌ アンチパターン:div をボタンに見せかける
<div className="btn" onClick={handleClick}>送信</div>

// ✅ button は「フォーカス可能・Enter/Space で発火・支援技術がボタンと認識」を無料で得る
<button type="button" onClick={handleClick}>送信</button>

押さえどころ:

  • ページ遷移は a(Next.js は Link)、アクションは button 見た目で選ばず、意味で選ぶ。
  • 見出しは階層を守る。 h1 は1ページ1つ、h2 → h3 を飛ばさない。スクリーンリーダー利用者は見出しでページを「拾い読み」します。
  • ランドマークで領域を示す。 header / nav / main / footer を使うと、支援技術がページ構造を提示できます。main は1つ。
  • リストは ul/ol、表は tablethscope 付き)。 見た目だけ似せた div は構造情報を失います。

セマンティック HTML は「後から ARIA で補う」より圧倒的に堅牢で、保守コストも低い。これは KISS そのものです。


4. キーボード操作とフォーカス管理

マウスを使えないユーザー(運動障害・スクリーンリーダー・パワーユーザー)にとって、キーボードだけで全機能に到達できることは生命線です。

4-1. すべての操作にキーボードで到達できるか

  • Tab で論理的な順序に移動でき、Enter/Space/矢印で操作できること。
  • tabindex0(フォーカス順に含める)か -1(プログラムでフォーカス可能)だけ。 正の tabindex はフォーカス順を壊すので使わない。
  • カスタムウィジェット(タブ、メニュー、コンボボックス)は WAI-ARIA Authoring Practices のキーボードパターンに従う。自作せず、Radix UI など検証済みのヘッドレス UI を使うのが安全で速い。

4-2. フォーカスは「見える」こと

/* ❌ 絶対にやってはいけない:フォーカスリングを消すだけ */
:focus { outline: none; }

/* ✅ マウス利用時は控えめ、キーボード利用時ははっきり見せる */
:focus-visible {
  outline: 2px solid currentColor;
  outline-offset: 2px;
}

4-3. ルート遷移・モーダルでのフォーカス移動

SPA/App Router ではページ遷移してもフォーカスが置き去りになりがちです。モーダルでは「開いたら中へフォーカス、閉じたら開いた要素へ戻す、背後を Tab で触れない(フォーカストラップ)」が必須です。

function Dialog({ open, onClose, children }: DialogProps) {
  const ref = useRef<HTMLDivElement>(null);
  const opener = useRef<HTMLElement | null>(null);

  useEffect(() => {
    if (open) {
      opener.current = document.activeElement as HTMLElement;
      ref.current?.focus(); // 開いたら中へ
    } else {
      opener.current?.focus(); // 閉じたら開いた要素へ戻す
    }
  }, [open]);

  // Escape で閉じる、フォーカストラップ等は Radix Dialog 等に任せるのが堅実
  return open ? (
    <div role="dialog" aria-modal="true" tabIndex={-1} ref={ref}>
      {children}
    </div>
  ) : null;
}

実務では、こうした挙動を完備した Radix UI の Dialog を使うのが最短かつ安全です(このサイトの UI も Radix ベースです)。車輪の再発明は YAGNI 違反になりがちです。


5. ARIA は「最後の手段」— 正しい使い方

ARIA は HTML だけでは表現できない動的な情報(展開状態、ライブ更新など)を補う道具です。乱用は逆効果になります。

ARIA の5つの鉄則(公式の "Rules of ARIA" の要約):

  1. ネイティブ HTML 要素があるなら、そちらを使う。 role="button" より button
  2. ネイティブの意味を ARIA で上書きしない。 <h2 role="tab"> のような破壊をしない。
  3. すべてのインタラクティブな ARIA はキーボードで操作可能に。
  4. フォーカスできる要素を role="presentation" / aria-hidden="true" で隠さない。(フォーカスできるのに支援技術から見えない、という矛盾を作らない)
  5. すべての操作要素にアクセシブルな名前を付ける。

よく使う正しい例:

// アイコンのみボタンには必ずラベルを
<button aria-label="メニューを開く" onClick={toggle}>
  <MenuIcon aria-hidden="true" />
</button>

// 開閉状態を伝える
<button aria-expanded={open} aria-controls="panel">詳細</button>
<div id="panel" hidden={!open}>...</div>

// 動的更新の通知(バリデーション結果やトースト)
<div role="status" aria-live="polite">{message}</div>

6. フォームのアクセシビリティ

フォームは a11y の失敗が最も多い場所です(詳細な実装はReact Hook Form × Zod 実践ガイドを参照)。最低限これだけは守ります。

  • すべての入力に labelhtmlFor で関連付け)。 placeholder はラベルの代わりにならない(入力すると消え、コントラストも低い)。
  • エラーは aria-invalidaria-describedby で入力欄に紐づけ、role="alert" で通知。
  • 必須は色だけに頼らない。 テキストや *+凡例で示し、aria-required を付ける。
  • 送信失敗時は最初のエラー項目へフォーカス。
<label htmlFor="email">メールアドレス</label>
<input
  id="email"
  type="email"
  aria-invalid={!!error}
  aria-describedby={error ? "email-error" : undefined}
/>
{error && <p id="email-error" role="alert">{error}</p>}

7. 色・コントラスト・モーション

色とコントラスト

  • 本文テキストは背景とのコントラスト比 4.5:1 以上(大きい文字は 3:1)。AA の必須基準です。
  • 色だけで情報を伝えない。 「赤=エラー」はアイコンやテキストと併用する(色覚特性への配慮)。

モーション(prefers-reduced-motion)

前庭障害のある人には、大きなアニメーションが体調不良を引き起こします。OS の「視差効果を減らす」設定を尊重します。このサイトのアニメーション層も prefers-reduced-motion を尊重する設計です。

@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}

React 側でも判定できます。

const reduced = useReducedMotion(); // motion ライブラリのフック等
<motion.div animate={reduced ? {} : { y: [20, 0], opacity: [0, 1] }} />

8. WCAG 2.2 の新基準(2026年に押さえるべき差分)

WCAG 2.2 で追加された 9 基準のうち、AA に影響する主要なものを実装観点で要約します。

基準レベル実装でやること
2.4.11 フォーカスの非遮蔽(最低限)AA固定ヘッダーや Cookie バナーがフォーカス中の要素を完全に隠さない
2.5.7 ドラッグ動作AAドラッグで行う操作に、クリック等の代替手段を用意する
2.5.8 ターゲットサイズ(最低限)AAクリック対象は原則 24×24px 以上、または十分な間隔を確保
3.2.6 一貫したヘルプA問い合わせ等のヘルプ導線をページ間で同じ位置・順序に
3.3.7 冗長な入力A同一手続き中で同じ情報を再入力させない(自動補完・引き継ぎ)
3.3.8 アクセシブルな認証(最低限)AAパスワード記憶やパズルを必須にしない。パスワード貼り付け・パスキーを許可

特に 2.5.8 ターゲットサイズ3.3.8 アクセシブルな認証 は、既存サイトが見落としがちです。小さなアイコンボタンの密集、貼り付け禁止のパスワード欄、CAPTCHA 必須のログインは、いずれも 2.2 で問題になります。


9. テスト戦略:自動 + 手動の二段構え

自動検査だけでは a11y 問題の3〜5割しか検出できません。自動で土台を守り、手動で体験を確認するのが正解です。

自動:axe を CI に組み込む

// tests/e2e/a11y.spec.ts (Playwright + @axe-core/playwright)
import { test, expect } from "@playwright/test";
import AxeBuilder from "@axe-core/playwright";

test("トップページに重大な a11y 違反がない", async ({ page }) => {
  await page.goto("/");
  const results = await new AxeBuilder({ page })
    .withTags(["wcag2a", "wcag2aa", "wcag22aa"])
    .analyze();
  expect(results.violations).toEqual([]);
});

開発中は eslint-plugin-jsx-a11y で静的に検出し、コンポーネント単位では jest-axe / vitest-axe を使うと、問題を早期に・安く潰せます(シフトレフト)。

手動:人にしか分からないこと

  • キーボードだけで全操作。 マウスを抜いて Tab・Enter・矢印・Escape で一周できるか。
  • スクリーンリーダー。 macOS の VoiceOver、Windows の NVDA で主要動線を聞く。
  • 拡大表示。 200% ズーム、400% 相当でレイアウトが破綻しないか。

10. アンチパターン(やりがちな失敗)

  • outline: none でフォーカスリングを消す(キーボード利用者が迷子になる)。
  • div/spanonClick だけ付けてボタン化(フォーカス・キーボード・役割がすべて欠落)。
  • placeholder をラベル代わりに使う。
  • ❌ 意味のない rolearia-* を盛る(「とりあえず ARIA」は害になる)。
  • ❌ 画像 alt を空にすべき装飾画像と、内容のある画像を区別しない(装飾は alt=""、意味のある画像は説明を)。
  • ❌ モーダルでフォーカストラップと復帰をしない。
  • ❌ アニメーションで prefers-reduced-motion を無視する。

11. FAQ(よくある質問)

Q. どのレベル(A/AA/AAA)を目標にすべき? A. 実務標準は AA です。多くの調達・ガイドラインが AA を基準にしています。AAA は一部基準のみ部分的に狙うのが現実的です。

Q. axe(自動検査)に通れば WCAG 準拠と言える? A. 言えません。自動検査は機械的に判定できる範囲(3〜5割程度)のみです。キーボード操作やスクリーンリーダーでの体験は手動確認が必要です。

Q. アクセシビリティ対応は SEO に効く? A. 効きます。見出し構造・代替テキスト・セマンティック HTML・明確なリンクテキストは、検索エンジンと支援技術の双方が読む情報源です。

Q. 既存サイトの a11y 改善はどこから手を付ける? A. ①セマンティック HTML への置換、②キーボード操作とフォーカス可視化、③フォームのラベル・エラー、④コントラスト、の順が費用対効果が高いです。自動検査で現状把握してから優先度を付けます。

Q. ヘッドレス UI(Radix 等)を使えば a11y は万全? A. 土台は大きく改善しますが万全ではありません。ラベル付与、コントラスト、コンテンツ構造、動線の一貫性はアプリ側の責任として残ります。


まとめ:アクセシビリティは「品質の総合点」

アクセシビリティは特別な専門領域ではなく、良い HTML・良い状態管理・良いフォーカス設計の積み重ねです。だからこそ、a11y が担保されたプロダクトは総合的な品質が高い。

  1. セマンティック HTML を使い切る(最大のレバー)。
  2. キーボード操作とフォーカス管理を全動線で保証する。
  3. ARIA は補助として正しく使う(誤用は無いほうがマシ)。
  4. フォーム・コントラスト・モーションで誰も取りこぼさない。
  5. WCAG 2.2 の新基準(ターゲットサイズ・アクセシブル認証など)を反映する。
  6. 自動 + 手動テストで継続的に守る。

これらは到達ユーザー数の拡大、調達要件の充足、SEO 改善、そして「丁寧に作られている」という信頼に直結します。

新規プロダクトのアクセシブルな設計、あるいは既存サイトの WCAG 2.2(AA)対応・改善が必要な場合は、お気軽にご相談ください。 下記の事例では、現場の多様なユーザーが日々使う業務システムを、操作性と品質を両立して設計・実装した過程を紹介しています。

友田

友田 陽大

وزیر (METI) ایوارڈ یافتہ پروڈکٹ کے ڈویلپر۔ TypeScript + Python + AWS کے ساتھ میں SaaS، صنعتی ڈیجیٹل تبدیلی اور پروڈکشن کے قابل جنریٹو اے آئی (RAG) تنہا ابتدا سے انتہا تک فراہم کرتا ہوں — تقاضوں کی تعیین سے انفراسٹرکچر اور آپریشن تک۔

Got a challenge?

From design to implementation and operations — solo × generative AI

Implementation like this article's, end to end from requirements to production. Start with a free 30-minute technical consult and tell me about your situation.

پروجیکٹ کی بنیاد پر کام اور تکنیکی مشاورت دونوں کے لیے دستیاب ہوں۔ 30 منٹ کی مفت مشاورت سے آغاز کریں۔

最短ルート:カレンダーから直接予約

相談内容が固まっている方は、フォーム送信よりその場で日程を確定する方がスムーズです。下記から空き時間をお選びください。

  • 30分のオンライン無料相談
  • Google Meet / Zoom / Microsoft Teams
  • NDA 商談前締結可・無理な営業はいたしません
無料相談の空き枠を予約する

یہ بھی پڑھنے کے قابل