- name
- site-audit
- description
- サイトのアクセシビリティ・ユーザビリティ・情報設計・デザインの点検。ローカルサーバを代表ページ分だけ巡回して axe・キーボード走査・実寸のスクリーンショットで測り、機械で拾えない部分は目で見る。「デザインを見てほしい」「アクセシビリティをチェックして」「情報設計を点検して」「見づらいところを探して」と頼まれたときに使う。個別の issue の実装は issue-workflow が担当。
# サイトの点検
**測れるものは測り、測れないものだけ目で見る。** 逆をやると、コントラスト比を目で
当てて外し、情報の優先順位を axe に聞いて何も出ない。
| 誰が見るか | 対象 |
| --- | --- |
| `audit.mjs` | WCAG の機械判定・タブ順・はみ出し・alt・見出し階層・メタ・転送量 |
| スクリーンショット | 見出しの階層・詰まり・折り返し・図の見え方 |
| 人(ページを読む) | 情報の優先順位・回遊の導線・語彙・初見の読者に伝わるか |
## 1. 準備(初回だけ)
playwright はブログの `package.json` に入れない(CI と `npm ci` の対象を増やしたくない)。
リポジトリ外に置く:
```sh
mkdir -p ~/.cache/site-audit && cd ~/.cache/site-audit && npm init -y
npm install playwright axe-core
npx playwright install chromium
sudo env "PATH=$PATH" npx playwright install-deps chromium # libnspr4 等が無いと起動しない
```
置き場所は `SITE_AUDIT_DEPS` で差し替えられる。日本語が豆腐になるときは `fonts-noto-cjk`。
## 2. サーバを立てる
| 何を見たいか | 立て方 |
| --- | --- |
| 今のソースの状態(テーマを触った後) | `make s` → `http://localhost:4000` |
| 公開されている形のまま(速い) | `python3 -m http.server 4001 -d public`(`public/` が古ければ先に `make g`) |
**テーマを直した直後に静的配信を見ない。** `public/` は前回のビルドなので、直した箇所が
出ていないのに「直っている」と読める。
## 3. 回す
```sh
node .claude/skills/site-audit/audit.mjs --base http://localhost:4000 --shots /tmp/shots
node .claude/skills/site-audit/audit.mjs /articles/20260518a/ --widths 375 # ページと幅を指定
```
- 既定は**ページ種を1枚ずつ12種 × 幅 375/768/1280**で45秒ほど。最新記事と著者ページは
トップから辿るので、URL を書き換える必要はない
- 幅は 375(モバイル)・768(タブレット。CLAUDE.md の `text-wrap: balance` の境目)・
1280(サイドバーが出る幅)。CSS の分岐がここに集まっている
- `--json <file>` で機械可読の出力。`--shots <dir>` のスクリーンショットは Read で見る
- エラーがあると exit 1。**ただし CI に入れない**(下の「意図的な例外」があるため、
人が読んで判断する道具として使う)
## 4. 出力を読む
`[ERROR]` は WCAG A/AA を落としているもの、`[WARN]` は落としてはいないが読者が損をするもの、
`[INFO]` は判断材料(数字)。**同じ所見はページ種と幅をまとめて1行**にしているので、
「ページ:」の並びが所見の広がり(1ページだけか、テーマ全体か)を表す。
直す場所は EJS か Stylus のどちらかで、対応は CLAUDE.md の「構成」で引く。
`[WARN] main 要素が無い` のようにページ種が並ぶものは、**部品ではなくレイアウトの側**の話。
### 誤検知として外してあるもの(外した理由つき)
- **`aria-hidden="true"` の中身**は支援技術に出ないので、名前も alt も求めない
(#2845 のサムネがこの形。求めると1ページで25件の空振りが出る)
- **24px 未満の的**は axe の `target-size` に任せる。自前で測ると「見えないがフォーカス
できる」ラジオ(#2852)や段落内のリンクを拾い、仕様の例外条件を持たないぶん誤検知が増える
- **外部の計測タグの通信エラー**(GA・はてな・X)はローカルでは必ず落ちるので数えない
- **フェードの収束を待ってから axe を回す。** CSS だけのタブ(#2852)の `.tab_content` は
読み込み直後 `opacity: 0.47` を通過し、その途中で測ると `ink-mute`(白地で 6.19)が
#777777 に混ざって「コントラスト 4.44 で AA 落ち」に見える。**実在しない色で報告する**
ので、この待ちを外さない
- **`#main` は `<main>` とは別に見る。** テーマは `<main>` の内側に
`<section id="main" tabindex="-1">` を置くので、`main` 要素で拾うと着地点でない側が当たる
### 所見にする前に確かめること
- **既に意図として決まっていないか。** `h2` の薄い罫線・`ink-faint` の下限・
現在地の表し方は CLAUDE.md の「CSS / 文字サイズの方針」が理由つきで持っている。
機械判定が引っかかっても、そこに書いてあれば所見ではない
- **色の話は `/specials/styleguide/` を見る。** コントラスト比は `_variables.styl` から
生成されているので、計算し直さない
- **1ページだけの所見か、全ページか。** 記事本文由来(alt 無しの画像・見出しレベルの飛び)は
記事を直す話で、テーマを触らない
## 5. 目で見る(機械で拾えないもの)
スクリーンショットと実際のページで見る。**axe が緑でも、ここが崩れていれば読者は困る。**
- **一覧で先に目に入る順**がサムネ→タイトル→説明になっているか。日付・著者・タグが
タイトルより強く見えていないか
- **記事に入る前に分かること。** 何の記事か(タイトル)、どの分野か(カテゴリ)、
連載の何本目か。一覧のカードでこれが読めないと、開いて戻る回数が増える
- **読み終えた読者の次の一手**が1つに絞れているか。関連記事・連載の前後・同著者・
タグが同じ強さで並ぶと、どれも選ばれない
- **カテゴリとタグの役の違い**が読者側から見えるか(カテゴリ18件は分野、タグは主題)
- **見出しが同着していないか。** 記事タイトルと本文 h2 が同じ大きさに見える幅が無いか
(#2599 で 320〜414px で起きていた)。実寸のスクショで見る。拡大では分からない
- **本文1行の字数。** `audit.mjs` が全角換算で出す。和文は35〜45字が読み下せる帯で、
モバイル(375px)では20字前後まで落ちる。**50字を超えると目が行頭に戻れない**
- **図・表・コードブロック**が幅375pxで枠から出ていないか、横スクロールの手がかりが見えるか
- **ダークモード**(#2746)で役が崩れていないか。面と線が同じ値になると1pxが青い筋に見える
- **初見の読者に何のサイトか伝わるか。** ヘッダーとトップの最初の画面(375px と 1280px の
ファーストビュー)だけを見て判断する
## 6. 報告の形
所見1つを4点で書く。**「直し方」まで書いて、直すのは別(issue-workflow)。**
```
所見: 一覧のサムネのリンクがタブ順に残っている
実測: 一覧・著者・アーカイブの6〜25件。幅375/1280 の両方
影響: キーボードと支援技術の読者が1ページで最大25回空振りする
直す場所: themes/future/layout/_partial/article.ejs の .thumb-link(#2845 と同じ形にする)
```
- 複数の所見を1つの issue にまとめない(1 issue 1 PR)
- **数を書く。** 「読みにくい」ではなく「幅375pxで4行以上になる記事が12%」。
CLAUDE.md の判断はすべて数で決まっているので、数の無い提案は比較できない
在 GitHub 查看