「Lighthouseのアクセシビリティスコアは100点なのに、スクリーンリーダーユーザーから『使いにくい』と言われてしまった」
このような「数値と体験の乖離」は、開発現場で珍しいことではありません。既存のチェックツールは優秀ですが、「コードの文法」をチェックするのみで「意味」までは理解しません。例えば、風景写真のalt属性が「画像001」でも、プログラム的には合格と判定されます。しかし、これではユーザーに何も伝わりません。
そこで今回は、LLM(大規模言語モデル)の「文脈理解力」と、ブラウザ自動操作ツール「Playwright」を組み合わせた、次世代のアクセシビリティ診断ツールを自作します。
Pythonを使えば驚くほどシンプルに実装できます。機械的なチェックの向こう側にある、利用者の体験に寄り添った「伝わるアクセシビリティ」を目指しましょう。
1. なぜ静的解析ツールだけでは不十分なのか:AIアプローチの必然性
実務の現場で利用されるツールと、今回開発するツールの役割分担を整理します。
構文エラー検知の限界と「意味」の理解
axe-coreやLighthouseなどの静的解析ツールは、以下のチェックに優れています。
- コントラスト比の基準を満たしているか
<img>タグにalt属性が設定されているか- フォーム要素にラベルが正しく紐付いているか
これらはアクセシビリティ改善の第一歩として非常に役立ちます。しかし、以下のような「文脈」が絡む問題には対応しきれないという課題は珍しくありません。
- 不適切な代替テキスト: 商品画像に「写真」とだけ記述されているケース。
- 過剰なARIA属性: ボタンのテキストで機能が明白なのに、冗長な
aria-labelが付与されているケース。 - 論理構造の矛盾: 見出しレベルが視覚的な階層と一致していないケース。
これらを正しく判断するには、「画像に実際に何が写っているか」「前後のテキストの意味は何か」という、ユーザーの体験に直結する文脈の深い理解が求められます。ここで、視覚情報を高度に処理できる最新のマルチモーダルAIが大きな力を発揮します。
本チュートリアルのゴール
今回作成するのは、以下の機能を持つPythonスクリプトです。
- Playwrightで対象ページにアクセスし、DOM(HTML構造)とスクリーンショットを取得。
- OpenAI APIを利用し、取得した視覚情報とコード情報を解析。WCAG(Web Content Accessibility Guidelines)基準に基づき、文脈を考慮した診断を実行。
- 具体的な修正案(より適切なaltテキストや修正コード)を含むレポートを出力。
ここで使用するAIモデルについて、最新の動向を踏まえた補足を加えます。OpenAIのモデル開発サイクルは非常に速く、2026年2月時点の標準モデルはGPT-5.2となっています。GPT-5.2は、100万トークン級の長い文脈理解、画像を含む高度なマルチモーダル処理能力、そして複雑な指示に対する精度の高い推論能力(ThinkingとInstantの自動ルーティングによる向上)を備えています。
注意点として、以前広く利用されていたGPT-4oやGPT-4.1などのレガシーモデルは、2026年2月13日をもってChatGPTでの提供が終了(廃止)されました。ユーザーの99.9%がすでに新しいモデルへ移行している背景もあり、これからツールを実装・運用する際は、安定した応答品質を持つGPT-5.2への移行が推奨されます。API経由での旧モデル利用は当面継続される見込みですが、長期的な運用を見据えれば最新モデルを前提とするのが安全です。
さらに、AIに具体的な修正コードを提案させるタスクでは、2026年2月に発表されたコーディング特化のエージェント型モデルGPT-5.3-Codexの活用も視野に入ります。ただし、APIの一般提供状況や仕様は日々変化するため、実装時は必ずOpenAIの公式ドキュメントで最新の状況を確認してください。
静的解析ツールで機械的にチェックできる土台を固め、AIの文脈理解力で実際の利用者の体験に寄り添った質を高める。この二段構えのアプローチこそが、これからのアクセシビリティ対応のスタンダードになると確信しています。
2. 開発環境のセットアップと依存ライブラリの導入
実際に手を動かしていきましょう。まずはPythonの開発環境を整えます。
Python環境とPlaywrightのインストール
必要なライブラリは主に3つです。
playwright: ブラウザ操作用openai: AIモデルへのアクセス用python-dotenv: APIキーなどの環境変数管理用
ターミナルで以下のコマンドを実行してください。
pip install playwright openai python-dotenv
playwright install
OpenAI APIキーの設定
セキュリティのため、APIキーは環境変数として管理します。プロジェクトのルートディレクトリに .env ファイルを作成し、以下のように記述してください。
OPENAI_API_KEY=sk-your-api-key-here
これで準備完了です。次に、診断対象のデータを取得する部分を作ります。
3. 実装Step 1:PlaywrightによるDOM要素の抽出とクリーニング
Webページ全体のHTMLをそのままAIに入力すると、トークン制限やノイズによる精度低下が発生します。そのため、診断に不可欠な情報だけを抜き出す前処理が欠かせません。
Pythonの非同期処理(async/await)とPlaywrightを組み合わせ、必要な要素を取得する手順を整理します。
診断に必要な要素のフィルタリング
以下のコードは、指定ページを開き、主要な画像要素(img)とその周辺の文脈を抽出する関数です。不可視の画像をスキップし、AIの判断に必要な「実際の見た目(スクリーンショット)」と「実装状況(コード)」を効率よく取得します。
import asyncio
import base64
from playwright.async_api import async_playwright
async def extract_image_elements(url):
async with async_playwright() as p:
# ブラウザをヘッドレスモード(画面表示なし)で起動
browser = await p.chromium.launch(headless=True)
page = await browser.new_page()
# ページにアクセスし、ロード完了まで待機
await page.goto(url)
# ネットワークのアイドル状態まで待つことで、遅延読み込み画像なども取得しやすくする
await page.wait_for_load_state("networkidle")
# 画像要素を取得
images = await page.query_selector_all("img")
extracted_data = []
for img in images:
# 視覚的に見えていない画像(display: noneなど)はアクセシビリティ診断の優先度が低いためスキップ
is_visible = await img.is_visible()
if not is_visible:
continue
# 現在のalt属性とsrcを取得
alt_text = await img.get_attribute("alt")
src = await img.get_attribute("src")
# 画像単体のスクリーンショットを撮影してBase64エンコード
# AIに「実際の見た目」を伝えるために不可欠な処理です
try:
img_buffer = await img.screenshot()
base64_image = base64.b64encode(img_buffer).decode('utf-8')
extracted_data.append({
"type": "image",
"src": src,
"current_alt": alt_text or "", # Noneの場合は空文字に統一
"image_base64": base64_image
})
except Exception as e:
# 画像読み込みエラーなどでスクリーンショットが撮れない場合はスキップまたはログ出力
print(f"Error processing image {src}: {e}")
continue
await browser.close()
return extracted_data
# 実行テスト用
# asyncio.run(extract_image_elements("https://example.com"))
ポイント:トークン節約と精度向上のための工夫
ページ全体のスクリーンショットではなく、診断対象要素ごとのスクリーンショットを個別に取得している点が重要です。これにより、AIモデルは「画像の配置意図」に集中でき、診断の正確性が向上します。さらに、不要なHTMLタグやスクリプトを除外することで、API送信データ量を最小限に抑え、運用コスト削減にもつながります。
4. 実装Step 2:ChatGPTのVision機能を用いた「alt属性」の診断と生成
本ツールの中心機能です。Playwrightで取得した画像データと現在のaltテキストをAIモデルに渡し、WCAG基準に照らし合わせて判定させます。
現在はマルチモーダル対応API(Vision機能)を活用することで、画像内容を高精度に解析し、文脈に沿った代替テキストの提案を受けられます。特に2026年以降の主力であるGPT-5.2モデルでは、画像理解や長い文脈の把握能力が大幅に向上しており、より精度の高いアクセシビリティ診断が可能です。
アクセシビリティ評価用プロンプトの設計
プロンプトエンジニアリングの質が診断結果を左右します。専門的な評価軸を持たせることが大切です。
- 役割の定義:「Webアクセシビリティの専門家(WCAG 2.1 AAレベル準拠)」と明記する。
- 基準の提示:「装飾目的か、情報伝達目的か」という判断基準を与える。
- 出力形式の指定:自動処理しやすいよう、JSON形式での出力を義務付ける。
以下は、OpenAI APIを使用した実装例です。
from openai import OpenAI
import os
from dotenv import load_dotenv
import json
load_dotenv()
client = OpenAI(api_key=os.getenv("OPENAI_API_KEY"))
def analyze_image_accessibility(image_data):
prompt = f"""
あなたはWebアクセシビリティの専門家(WCAG 2.1 AAレベル準拠)です。
以下の画像の代替テキスト(alt属性)を評価してください。
現在のaltテキスト: "{image_data['current_alt']}"
以下のJSONフォーマットのみで回答してください。
{{
"is_appropriate": boolean, // 適切ならtrue
"reason": "string", // 判定理由(日本語)。なぜ適切/不適切なのか具体的に。
"suggested_alt": "string", // 推奨されるaltテキスト
"image_type": "string" // "informative"(情報あり), "decorative"(装飾), "functional"(機能あり)のいずれか
}}
判断基準:
- 装飾目的の画像(背景パターンや区切り線など)ならaltは空文字("")が適切。
- 情報を持つ画像なら、その内容を簡潔かつ具体的に説明すること。
- "画像"や"photo"などの冗長な言葉は含めないこと。
- 機能を持つ画像(リンクやボタン)の場合、見た目ではなく「機能や目的」を説明すること。
"""
# 最新のVision機能を持つモデルを指定してください
# モデル名は頻繁に更新されるため、実装時は公式ドキュメントで最新IDを確認してください
response = client.chat.completions.create(
model="ChatGPT", # 例: 最新のVision対応モデルを指定(適宜最新版に置き換えてください)
messages=[
{
"role": "user",
"content": [
{"type": "text", "text": prompt},
{
"type": "image_url",
"image_url": {
"url": f"data:image/jpeg;base64,{image_data['image_base64']}"
}
}
]
}
],
response_format={"type": "json_object"}, # JSONモードを有効化して解析エラーを防ぐ
max_tokens=500
)
return json.loads(response.choices[0].message.content)
モデル選択と実装のポイント
この関数により、「ファイル名がそのまま入ったalt(例: DSC001.jpg)」や「画像情報と乖離したalt」を自動検出し、具体的な改善案を得られます。
実装時の注意点:
- モデルの選択:画像認識に対応したVisionモデルが必須です。OpenAIのAPIを利用する場合、GPT-5.2(InstantまたはThinking)などの最新モデルを指定してください。なお、以前利用されていたGPT-4oやGPT-4.1などの旧モデルは2026年2月に廃止されているため、既存のシステムを運用している場合はAPIのモデル指定を更新する移行作業が必要です。
- JSONモード:
response_format={"type": "json_object"}を指定し、確実なJSON形式での返答を制御します。
AIによる診断は強力な補助手段ですが、最終決定権は人間が持つべきです。このツールを「一次スクリーニング」として位置づけるのが実用的です。
5. 実装Step 3:ARIA属性とインタラクションの論理診断
ボタンやフォームなどのインタラクティブな要素が、スクリーンリーダー利用者に正しく伝わるかも重要なチェックポイントです。HTMLコードの構造を読み解き、WAI-ARIA(aria-labelやroleなど)の使い方が適切かを診断します。
不適切なrole属性やaria-labelの検出
画面上はボタンに見えても、キーボード操作を受け付けない実装は珍しくありません。以下のコードは、そうした論理的な構造の不整合を見つけ出します。
async def analyze_aria_logic(html_snippet):
# プロンプト:HTML構造とARIA属性の整合性をチェック
prompt = f"""
以下のHTMLスニペットにおけるWAI-ARIA属性およびHTML構造のアクセシビリティを診断してください。
HTML:
{html_snippet}
特に以下の点に注意して分析してください:
- ネイティブ要素(<button>, <a>など)で十分な場合に、冗長または誤ったrole属性がないか。
- aria-labelが視覚的なテキストや文脈と矛盾していないか。
- インタラクティブな要素(divやspanでのボタン実装など)に、適切なキーボード操作(tabindex, keydown)が可能そうな構造か。
JSON形式で以下のキーを含めて出力してください:
{{
"issues_found": boolean,
"details": "問題点の詳細(スクリーンリーダー利用者の視点での影響を含む)",
"fixed_html": "修正後の推奨HTMLコード(最小限の修正で)"
}}
"""
# テキスト解析のみであれば、コストパフォーマンスに優れた軽量モデルが推奨されます
# ※最新の軽量モデル(例: ChatGPT(軽量版)等)を使用してください
response = client.chat.completions.create(
model="別のAIサービス(軽量版)", # コスト効率の良い最新モデルを指定
messages=[{"role": "user", "content": prompt}],
response_format={"type": "json_object"}
)
return json.loads(response.choices[0].message.content)
テキスト解析に特化したモデルを活用することで、大量のコード断片を素早くチェックできます。
例えば、div タグに onclick イベントだけを設定した実装に対し、AIは以下のような指摘を返します。
- 問題の指摘:「
div要素は標準ではキーボードフォーカスを受け取れず、スクリーンリーダー利用者にボタンとして認識されません。」 - 修正案:「セマンティックな
<button>タグに置き換えるか、role="button"とtabindex="0"を追加し、キーボード操作用のイベントハンドラも実装してください。」
「なぜ障壁になるのか」という理由と「具体的な修正コード」をセットで提示することで、チーム全体の理解が深まります。
注意:使用するAIモデルは、プロジェクトの要件や予算に合わせて最適なものを選択してください。モデルの性能や料金体系は変動するため、定期的に公式サイトを確認することをお勧めします。
6. CI/CDパイプラインへの統合と運用上の注意点
優れた診断ツールも、日々の開発フローに組み込まれなければ継続的な効果は発揮できません。GitHub ActionsなどのCI/CDパイプラインに統合し、自動的にチェックが実行される仕組みを整えることが求められます。
最新の開発環境では、Visual Studio CodeのAgent Skillsや、Claude Code Securityのような自律型エージェント機能が登場しており、高度な自動化が可能です。
コスト管理とGitHub Actionsの活用
全ページの全画像を毎回スキャンすると、API利用コストが膨らみ、CIの実行時間も長引きます。効率的な運用には以下のアプローチが有効です。
- 差分実行:Gitの変更履歴を参照し、変更が加わったファイルのみを診断対象に絞り込みます。
- キャッシュ戦略:画像のハッシュ値をキーに過去の診断結果をキャッシュし、無駄なAPIリクエストを省きます。
- マルチモデルの使い分け:GitHub Copilotがマルチモデル対応を果たしたように、用途に応じたモデル選択がトレンドです。単純なHTML構造のチェックには軽量モデル、複雑な画像の文脈理解には高度なVisionモデルを割り当て、コストと精度のバランスを最適化します。
定期的なNightlyビルドで全量チェックを行い、Pull Request作成時は差分チェックのみに留める使い分けが実用的です。
AIハルシネーション(誤検知)への対処とチーム連携
AIは文脈を深く読み取る能力に長けていますが、誤った指摘(ハルシネーション)を返すリスクもあります。
そのため、出力結果を「絶対的な正解」として扱い、自動でコードを修正してマージする運用は避けるのが賢明です。あくまで「人間のレビュアーに気づきを与える提案」として活用します。
GitHub Actionsでの連携例として、診断結果をPull Requestのコメントとして自動投稿するワークフローを構築します。「AIが改善案を提示しています。本来の意図と合致しているか確認してください」というスタンスで通知することで、開発者は心理的負担なく提案を受け入れることができます。
まとめ:技術で「思いやり」をスケーリングする
今回取り上げたAIとPlaywrightを組み合わせた診断アプローチは、人間の仕事を奪うものではありません。むしろ、開発者が「より創造的で、人間的な配慮が求められる領域」に集中する時間を生み出す仕組みです。機械的なチェックはAIに任せ、私たちはより本質的なユーザー体験(UX)の議論に時間を投資するべきです。
アクセシビリティの向上は、一度ツールを導入して終わりではありません。自動化ツールがもたらす最大の価値は、チーム全体のアクセシビリティに対する意識の底上げにあります。具体的な修正案と理由が日常的に提示される環境を作ることで、開発者自身が自然とインクルーシブな実装手法を学んでいくサイクルが生まれます。
まずは主要な数ページから小さく始め、チームの状況に合わせて少しずつ診断の範囲を広げていくことをお勧めします。技術の力で思いやりを仕組み化し、すべての人が快適に利用できるデジタル環境を構築していきましょう。きっと、これまで見落としていた改善のヒントが見つかるはずです。それが、より多くのユーザーを歓迎するWebサイトへの第一歩になります。
API公式リソース
最新のモデル仕様や移行手順については、これらの公式情報をご確認ください。
コメント