アクセシビリティ後付けで失敗した話──3年の実装記から学んだこと

Webサイトのアクセシビリティ対応、実は後付けすると大変です。うちのチームが3年かけて経験した失敗と成功、スクリーンリーダー検証の現実を実務ベースで語ります。

「あ、アクセシビリティ対応してないんだ……」

プロジェクトが本番1年経った時点で、営業から連絡が来た。「大手企業さんがうちのサイト使えないって言ってるんですけど」。

スクリーンリーダーで読めていないページが大量にあった。画像に代替テキストがない、ボタンのラベルが不正、フォーカス順序が意味不明……。最悪な状態だった。

それがきっかけで、うちのチームは3年間アクセシビリティと格闘することになった。正直、最初は「ユーザーの5%未満だろ」くらいの認識だった。でも気づいたら、コード品質、テスト体制、チーム文化全てが変わってた。

アクセシビリティは最初は「コスト」だと思ってた

初期段階で僕たちが取り組んだのは、とにかくWCAG 2.1 AA対応だった。でも正直、最初の6ヶ月は地獄だった。

既存のHTMLを全部見直す。<button>に見えても実は<div onclick>だ。画像にはaltが必須だけど、なぜか3000個の画像全部に「image」とだけ書いてある。フォーム要素のラベルがない。キーボード操作ができない。

当時のメンバーの反応は「こんなの全部直すのに何ヶ月かかるんだよ……」だった。実際に試算したら、3ヶ月フルリソースで対応しても、カバーできるのは既存ページの60%。

その時の失敗

取り組み当初は、いくつか痛い判断をしてしまった:

  • 全ページ一括対応を目指した(分割実装すべきだった)
  • 静的チェック(Axe)のみに頼った(実ユーザーテストなし)
  • デザイナーにアクセシビリティ知識がなかった
  • CIに組み込まなかった(後で属人的になった)

こういった試行錯誤を通じて、ようやく正しいアプローチが見えてきた。

転機は「誰が使えないか」を実際に見たとき

4ヶ月目に、実際に視覚障害者のユーザーにテストしてもらう企画をやった。JAWS(スクリーンリーダー)を使ってサイトを実際に操作してもらう。

「え、これ読める……?」

ボタンのaria-labelがないから、「ボタン」としか聞こえない。フォーム送信ボタンをタブで探してるのに、見つけるのに2分かかる。画像は全部「image」と読み上げられる。

その日、チームの温度が一気に変わった。「これ、ユーザーの視点だとこうなってるんだ」という現実が、スライド資料の100回分より効いた。

以降、月1回のスクリーンリーダーテスト会が定例化した。これが本当に重要だったんですよね。

2年目:自動化とチーム体制の見直し

アクセシビリティ対応を持続可能にするには、自動化とルール化が不可欠だと気づいた。ここからが、ようやく「実装体制」が整った段階。

CIに組み込んだチェック

1年目は手動チェックばかりだったけど、これは絶対に続かない。以下の自動ツールをCIパイプラインに組み込んだ:

// package.json の例
{
  "scripts": {
    "test:a11y": "axe --exit-code 1 --follow-links",
    "test:lighthouse": "lighthouse --only-categories=accessibility",
    "test:pa11y": "pa11y-ci --config .pa11yci.json"
  },
  "husky": {
    "hooks": {
      "pre-push": "npm run test:a11y && npm run test:lighthouse"
    }
  }
}

Axe DevTools + lighthouse-ci + pa11y-ci の3つで、プルリクエスト段階で問題を検出する体制にした。地味だけど、この仕組みがないと本当に属人化する。

スクリーンリーダーテストの定期化

実ユーザーテストは月1回だけにして、その間は開発チームが WebAIM スクリーンリーダー検証リストで簡易チェック。毎週自動で実行される。

# 毎週水曜に自動実行
schedule:
  - cron: "0 10 * * 3"
    
jobs:
  a11y-test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/setup-node@v3
      - run: npm ci
      - run: npm run test:a11y
      - run: npm run test:lighthouse -- --output-path=./lighthouse.json
      - uses: actions/upload-artifact@v3
        with:
          name: a11y-reports
          path: ./lighthouse.json

3年目:WCAG 2.1 AAはゴールではなく基本

2年で WCAG 2.1 AA をほぼ達成した時点で、むしろ難しい問題が見えてきた。そこからが本当の勝負だったんだ。

カラーコントラスト設計の現実

WCAG要件は「テキストとの比率 4.5:1」。でも実際には……

/* これは技術的には OK だけど */
.subtitle {
  color: #777;
  background: #fff;
  /* コントラスト比: 4.54:1 */
}

/* 実際に視認すると結構キツい */
/* 薄い灰色背景では、もっと濃い色が必要 */

WCAG AAは「最低限」に過ぎない。実務では AAA(7:1)を目指すか、より視認性の高い色設計が必要。実際に見比べると、その差は一目瞭然。

うちのチームは最終的に、全ページのカラーシステムを再設計した。デザイナーと開発者で「WCAG AA以上 + 実ユーザー検証」を基準にした。

キーボード操作フローの複雑性

// フォーカスシステム設計の失敗例
const handleKeyDown = (e) => {
  if (e.key === 'Enter') {
    // ここでモーダルを開く
    openModal();
    // でも、フォーカスをモーダル内に移動するのを忘れた
  }
};

// 正解版
const handleKeyDown = (e) => {
  if (e.key === 'Enter') {
    openModal();
    // 次のチックでモーダル内の最初の入力フォーカスに移動
    setTimeout(() => {
      const firstInput = modalRef.current?.querySelector('input');
      firstInput?.focus();
    }, 0);
  }
};

Tabキーでの移動順序、フォーカストラップ(モーダル外に出ないようにする)、aria-liveでの動的更新通知。こういった細かい実装が、スクリーンリーダーユーザーの体験を大きく左右する。小さな工夫の積み重ねなんですよね。

チーム体制の工夫

役割分担を明確にした

最初は「誰かがアクセシビリティを見る」という曖昧な体制だった。3年目には以下のように整理した:

役割責務頻度
フロントエンド開発者HTML/CSSのセマンティック実装、aria属性毎PR
デザイナーカラーコントラスト、フォントサイズ、レイアウトデザイン段階
QAエンジニア自動ツール実行、簡易スクリーンリーダーテスト毎スプリント
PMスクリーンリーダーユーザーテスト実施月1回

役割を明確にするだけで、「誰かやってくれてるだろ」という責任転嫁が減る。全員が自分のフェーズで気をつけるようになった。

学習投資

アクセシビリティはチーム全体のスキルである必要がある。毎月30分の勉強会を開催した。

最初の数ヶ月は外部講師を招いたけど、1年目終盤からはチームメンバーが自分たちで事例共有するようになった。「このコンポーネントはこうやって対応した」みたいな。

2026年時点での「アクセシビリティ対応」の現実

この3年で気づいたことがある。アクセシビリティ対応は、単なるコンプライアンスではなく、コード品質向上の手段だということ。

セマンティックHTMLの威力

<!-- 悪い例 -->
<div onclick="navigate()" role="button" tabindex="0" aria-label="ホーム">
  Home
</div>

<!-- 良い例 -->
<a href="/">Home</a>

セマンティックなHTMLを書くことで、スクリーンリーダーの対応は自動的についてくる。同時に、ブラウザのネイティブ動作(キーボード対応など)も自動で働く。

これは結果的に、バグが少ない、テストしやすい、メンテナンスしやすいコードになる。正直、アクセシビリティを意識した開発って、別にアクセシビリティユーザーだけのものじゃなくて、全員にとって良いんだなって。

実装パターンの確立

3年運用して、チーム内で「アクセシビリティ対応パターン集」ができた。新入りが来ても、このテンプレートを使えば最初からアクセシビリティを組み込んだコードが書ける。

// フォーム入力のテンプレート
export const AccessibleInput = ({
  label,
  id,
  error,
  helperText,
  ...props
}) => (
  <div className="form-group">
    <label htmlFor={id}>{label}</label>
    <input
      id={id}
      aria-describedby={error ? `${id}-error` : undefined}
      aria-invalid={Boolean(error)}
      {...props}
    />
    {error && (
      <p id={`${id}-error`} role="alert">
        {error}
      </p>
    )}
    {helperText && (
      <p id={`${id}-helper`} className="helper-text">
        {helperText}
      </p>
    )}
  </div>
);

こんな感じで、「正しいパターン」を最初から提供することで、属人化を防げる。

正直なところ、まだ課題は残ってる

完璧なアクセシビリティは存在しない

正直、3年やってもWCAG 2.1 AAA完全対応には至ってない。リッチなUIコンポーネント(データテーブル、複雑なモーダル、動的レイアウト)は、アクセシビリティとの緊張関係が常にある。

完璧を目指すと、プロダクト開発そのものが止まっちゃう。だから現実的には「優先度をつけながら少しずつ」という感じ。

アクセシビリティはコスト

だから、プロダクトのステージによって優先度を分ける必要がある。初期段階はMVP的なアプローチ(基本のHTML/CSS対応)で、ユーザーが増えてから本格的に投資する、というのが現実的。

新規プロジェクトなら「最初から対応」で最小コストだけど、既存大規模サイトなら「段階的対応」を検討すべき。

ユーザーとのコミュニケーション

最後に気づいたのは、アクセシビリティ対応を伝えることの難しさ。外部的には「WCAG 2.1 AA対応」と書くけど、実際のユーザーが感じる「使いやすさ」はそれ以上に大事。

スクリーンリーダーユーザーの生の声を定期的に聞く環境があると、チーム全体の動機づけが全く違う。「この機能は本当に使えてますか?」って直接聞くと、統計データには出ない問題が見えてくる。

まとめ

3年間Webチームでアクセシビリティに取り組んで気づいたことを3つ:

  1. アクセシビリティは後付けできない ──HTML設計、カラー設計の段階から組み込まないと、後から修正するのに何倍ものコストがかかる。次のプロジェクトからは、最初から組み込むべき。

  2. 自動ツール + 実ユーザーテストの両輪が必須 ──Axe や Lighthouse は大事だけど、スクリーンリーダーユーザーの生の反応を定期的に見ることで、チームの意識が圧倒的に変わる。机上の知識と現実のギャップは想像以上だったんだ。

  3. チーム全体の理解が最重要 ──デザイナーがカラーコントラストを意識する、開発者がセマンティックHTMLを書く、QAが確認する。これが全て揃わないと続かない。1人のアクセシビリティの担当者がいても、チーム全体が関心なかったら意味ない。

アクセシビリティは、ユーザーの一部を排除しないための最低限の配慮だ。でも同時に、コード品質を高め、チーム全体のスキルを向上させる投資でもある。

次のプロジェクトに関わるエンジニアの皆さんへ:初期段階で「最初はアクセシビリティなしでいこう」という判断は、後々の技術負債になります。最初から組み込む労力と、後から修正する労力を比べたら、前者が絶対に正解です。僕たちも最初から対応してたら、3年間のうち1年半は別のことに使えてたんじゃないかな。

U

Untanbaby

ソフトウェアエンジニア|AWS / クラウドアーキテクチャ / DevOps

10年以上のIT実務経験をもとに、現場で使える技術情報を発信しています。 記事の誤りや改善点があればお問い合わせからお気軽にご連絡ください。

関連記事