3 行まとめ
- Claude Code に UI レビューまで任せたら、手動スクショに溶けていた 週 2.5 時間が 0 分になった
- Playwright で 3 枚撮影(FV / 全体 / モバイル)→ Claude Code が
Readツールで画像を見て 7 観点で判定する構成。Computer Use は重すぎて却下 - 一番効いたのは AI 感チェック(テンプレ見出し・eyebrow text・Why-choose-us パターン検出)。
code-reviewスキルから自動で呼び出すループ化で、改修 → UI レビュー → 改修が人手なしで回る
AI と一緒に開発していると、おかしな現象が起きるようになった。コードレビューは通るのに、ブラウザで開くと「なんか AI 感ある」UI になっている。型もエラーもない。code-review スキル(Claude にコードレビューさせるやつ)も「問題なし」と返す。でも画面はテンプレ感丸出しだったり、モバイルで微妙に崩れていたり、タップターゲットが小さかったりする。
要するに 「コードは書いた、でも画面は誰も見ていない」 状態が発生していた。AI が書いて AI がレビューして、人間は流し見してマージする。視覚的な確認だけが宙に浮いていた。
最初は手動でスクショを撮って Claude Code に渡していた。これがめちゃくちゃ時間を吸う。1 ページの撮影&共有で約 5 分、1 コミットで触るページが 3 つ、改修ループが 5 回回れば 5 分 × 3 × 5 = 75 分。週に UI を 2 本触れば、週 2.5 時間が手動スクショに溶ける計算になる。
Anthropic の Computer Use(Claude にブラウザを直接操作させる仕組み)を最初は本命視した。が、結論から言うと Computer Use は使わず、Playwright で撮ったスクショを Claude Code に Read させる構成に倒した。これで 75 分が 0 分になり、改修 → UI レビュー → 改修のループが人手を介さず回るようになった。
この記事では、なぜ Computer Use を選ばなかったか、Playwright + Claude Code でどう自走ループを組んだか、実際に何が検出されたかをまとめる。
なぜコードレビューだけでは UI を守れなかったか
とあるデータ可視化系の Web プロダクトを Astro + Cloudflare Pages で個人開発している。フロントエンドは Claude Code でガンガン生成・改修している。
開発フローはこう組んでいた。
- 変更が出たら
code-reviewスキルを走らせる - 型エラー・バグ・セキュリティ・設計逸脱を Claude にレビューさせる
- OK ならコミット
code-review スキルの責務は「コード」だ。具体的にはこんな観点を見ている。
### CRITICAL(ブロック必須)
- ハードコードされた APIキー・個人情報
- XSS / SQL インジェクション等の脆弱性
- 商用NGのデータソースを使っているコード
### HIGH
- 関数が50行超 / ファイルが800行超
- エラーハンドリングなし(外部API呼び出し、DB操作)
- pydantic の型が未定義または `Any`
### MEDIUM
- SEO メタ・JSON-LD の欠落
- console.log / print() が残っている
完全にコードベースの観点しかない。実レンダリングを見ない。
これで何が起きたかというと、
- セクション見出しが「〇〇が選ばれる理由」みたいなテンプレ的な汎用文言になっていた
- H1 の直上に uppercase + letter-spacing の eyebrow text(「Disaster Risk Intelligence」みたいな英語の飾り文字)が入っていた
- ハンバーガーメニューが 36px しかなくてタップしづらかった
- 検索ボックスのプレースホルダーがモバイルで切れていた
- ロゴ画像のサイズ指定を忘れて、Astro が画像を巨大な WebP に変換して LCP が悪化していた
全部「コードは正しい」変更だ。型もリンタも通る。code-review スキルでは引っ掛からない。
これを毎回手動で「ブラウザ開いて、スクショ撮って、Claude Code に共有」するのが面倒すぎて、自動化が必要になった。
最初の運用:手動スクショで Claude Code に渡していた
Claude Code はマルチモーダル対応している。画像ファイルを Read ツールで読ませると、画面を「見て」コメントを返してくれる。これを使えば手動でもUI レビューはできる。
実際にしばらくこれで運用していた。
-
npx astro devで dev サーバを立ち上げる - Chrome でページを開く
- デスクトップ表示でスクショを撮る(ファーストビュー)
- ページ全体のスクショも撮る
- DevTools でモバイルビュー(iPhone 12 Pro 相当)に切り替えてもう 1 枚
- 3 枚を
/tmp/に保存 - Claude Code に「以下の画像を見て、UI に問題ないかレビューして」と投げる
- 画像パスを 3 つ貼る
これで 1 ページ約 5 分かかる。慣れても 3 分は切れない。
ところが、1 コミットで触るページは大抵 3 つ前後ある。
- 共通レイアウト(BaseLayout.astro)を触れば → トップページ + エリア詳細ページの両方を確認
- 共通コンポーネント(HeroSection.astro 等)を触れば → 複数ページに波及
- グローバル CSS を触れば → ほぼ全ページに影響
さらに「修正 → 確認 → また修正 → 再確認」の改修ループが 5 回くらいは回る。これを全部手動でやると 5 分 × 3 ページ × 5 コミット = 75 分。
75 分は重い。重すぎて、途中で「もういいや」と省略するようになる。省略すると、また AI 感 UI とモバイル崩れが混入する。元の木阿弥だった。
Computer Use を検討して却下した
ちょうど Anthropic の Computer Use(Claude にブラウザ操作を任せる API)が話題になっていた。「これに全部任せれば、自分は何もしなくていいのでは?」と思った。
Computer Use はこう動く。
- 仮想ブラウザのスクショを撮る
- Claude にスクショを送る
- Claude が
{"action": "click", "coordinate": [342, 198]}のような構造化アクションを返す - それを実行して新しいスクショを撮る
- ループ
「UI レビューを Claude にやらせるなら、Claude にブラウザを直接操作してもらうのが筋なのでは?」と最初は思った。
調べてみたら、特性が UI レビュー用途には合わなかった。
1 アクションあたりのコストと時間
- 1 アクション往復で 2〜5 秒かかる(スクショ送信 + 推論 + アクション返却)
- 50 ステップのタスクで 2〜4 分
- スクショ 1 枚あたりトークン消費は Sonnet 4.6 で約 $0.0047(1568 トークン上限)
- 改修ループが何十回も回れば、トークン課金が累積する
精度
- OSWorld ベンチマークで Opus 4.7 が 72.5%
- 動的 UI・モーダル・ローディング状態が絡むと 50〜60% に落ちる
- 「確認ダイアログを延々クリックし続ける」みたいな詰まり方をする
構造的な弱点
- スクショ経由でしか状態を読めない(DOM 盲目問題)
- ビューポートに収まる範囲しか「見えない」
- 同じ入力で同じ出力を返さない(非決定的)
ここで気づいた。UI レビューに必要なのは「ブラウザを操作すること」じゃない。必要なのは「画面を見て、これでいいか判断すること」だ。
Computer Use はインタラクションのループにコストを払う設計になっている。一方、UI レビューは「画面を 3 枚撮って、それを見て判断するだけ」で済む。わざわざ Claude にマウスを握らせる必要がなかった。
Computer Use を本気で使うなら、フォーム入力 → 送信 → 結果確認 のような 動的インタラクション が必要な用途だ。ボタンの色やレイアウトが正しいかを見るだけなら過剰装備だった。
Playwright + Claude Code に倒した
最終的に倒した先はこうだ。
- スクショ撮影は Playwright に任せる(無料・高速・決定的)
- 判断は Claude Code に任せる(マルチモーダルで画像を Read する)
- 2 つを 1 つの Skill にまとめて、
code-reviewスキルから自動呼び出しする
構成図はこう。
git diff --name-only HEAD
↓
code-review スキル(コード観点でレビュー)
↓
(site/src/ のフロントファイル変更を検知)
↓
layout-check スキル を自動呼び出し
↓
1. dev server 起動確認
2. Playwright で 3 枚撮影(FV / 全体 / モバイル)
3. layout-check.mjs で自動検出(コンソールエラー・タップターゲット等)
4. Claude Code が Read ツールで画像を読む
5. 7 観点でUI レビューを書く
ポイントは 「Claude にブラウザを触らせない」 こと。Playwright が画面を撮ってくれれば、あとは画像ファイルを Claude Code が読むだけで済む。
Playwright 側のスペックも軽い。
- スクショ 1 枚の取得は数百ミリ秒
- 3 枚撮っても 1〜2 秒
- API コスト 0 円(ローカルで動くだけ)
- 同じ URL に対して同じスクショを返す(決定的)
実装の中身
実装は .claude/skills/layout-check/ 配下に 2 ファイルだけ置いた。
.claude/skills/layout-check/
├── SKILL.md # Claude Code への指示書(UI レビューの観点)
└── layout-check.mjs # Playwright スクリプト(自動検出)
layout-check.mjs(Playwright で自動検出)
Playwright で取れる「機械的に判定できる項目」はこちら側で先に潰す。Claude Code に頼むのはマルチモーダルが必要な部分だけにする。
// layout-check.mjs(抜粋)
import pkg from 'playwright';
const { chromium } = pkg;
const TARGET_URL = process.argv[2];
const LABEL = process.argv[3] || TARGET_URL;
const browser = await chromium.launch();
// デスクトップチェック(1440x900)
const desktop = await browser.newPage();
await desktop.setViewportSize({ width: 1440, height: 900 });
const consoleErrors = [], networkErrors = [];
desktop.on('console', msg => {
if (msg.type() === 'error') consoleErrors.push(msg.text());
});
desktop.on('pageerror', err => consoleErrors.push('[JS例外] ' + err.message));
desktop.on('response', resp => {
if (resp.status() >= 400 && !isDevNoise(resp.url())) {
networkErrors.push(`HTTP ${resp.status()} → ${resp.url()}`);
}
});
await desktop.goto(TARGET_URL, { waitUntil: 'networkidle', timeout: 25000 });
// 壊れた画像の検出
const brokenImages = await desktop.evaluate(() =>
Array.from(document.querySelectorAll('img'))
.filter(img => !img.complete || img.naturalWidth === 0)
.map(img => img.getAttribute('src') || img.src)
);
// 横スクロール検出
const hasHorizontalOverflow = await desktop.evaluate(() =>
document.documentElement.scrollWidth > document.documentElement.clientWidth
);
ここで取っているのは以下。
- コンソールエラー(JS 例外も含む)
- ネットワークエラー(HTTP 4xx / 5xx)
-
壊れた画像(
naturalWidth === 0の<img>) -
横スクロール(
scrollWidth > clientWidth)
次にモバイル(390x844)で タップターゲット 44px 未満 を検出する。WCAG 2.5.5 の最低基準だ。
const smallTargets = await mobile.evaluate((skipList) => {
// アウトラインボタン(枠線あり+透明〜白系背景)を補助ボタンと動的判定する。
// プライマリボタンは塗りつぶし、セカンダリは枠線のみというデザイン原則を利用。
function isSecondaryStyleButton(el) {
const s = window.getComputedStyle(el);
const m = s.backgroundColor.match(/rgba?\((\d+),\s*(\d+),\s*(\d+)(?:,\s*([\d.]+))?\)/);
if (!m) return false;
const alpha = parseFloat(m[4] ?? '1');
const [r, g, b] = m.slice(1, 4).map(Number);
if (alpha < 0.2) return true; // ゴースト
const isLight = r > 200 && g > 200 && b > 200;
if (isLight) return true; // アウトライン / タブ系
return false;
}
const els = Array.from(document.querySelectorAll('button, a, input[type="submit"]'));
const results = { critical: [], secondary: [] };
els.forEach(el => {
const rect = el.getBoundingClientRect();
// ...省略
if (rect.width >= 44 && rect.height >= 44) return;
if (isSecondaryStyleButton(el)) {
// WCAG 2.2 AA (2.5.8) は 24px 以上で適合。アウトラインは 24px 未満のみ報告
if (rect.width < 24 || rect.height < 24) results.secondary.push(/* ... */);
} else {
results.critical.push(/* ... */);
}
});
return results;
}, FOOTER_SKIP);
実装で工夫したのは プライマリ/セカンダリの動的判定 だ。最初は全てのボタンを 44px 必須にしていたが、これだと「ソート用の小さなアウトラインボタン」が大量に CRITICAL として上がってきて、毎回ノイズが多すぎた。
CSS の background-color を見て、塗りつぶされている(プライマリ)か、透明・白系背景(セカンダリ)かを判定し、セカンダリは WCAG 2.2 AA の 24px 基準まで緩めている。これで誤検知が劇的に減った。
スクリプトの実行は CLI 一発。
node .claude/skills/layout-check/layout-check.mjs \
"http://localhost:4321/tokyo/shinjuku/nishishinjuku/" "新宿区西新宿"
出力はこんな感じになる。
=== 自動検出結果 [新宿区西新宿] ===
コンソールエラー: なし
ネットワークエラー: なし
壊れた画像: なし
横スクロール発生 (1440px): なし
タップターゲット44px未満 (390px):
button "ハンバーガー" (36x36px)
a "比較に追加" (40x40px)
AA違反(補助ボタン): button "並び替え" (22x22px)
ここまでが「Playwright だけでわかる範囲」。ここから先が Claude Code の出番になる。
SKILL.md(UI レビューの 7 観点)
SKILL.md には、Claude Code が 画像を Read した後にどう判定するか を 7 観点で定義した。これは Claude Code が読むファイルで、コードじゃない。「指示書」だ。
7 観点は以下。
- A. ファーストビュー:5秒ルール、CTA が画面内にあるか、Hero が冗長すぎないか
- B. レイアウト崩れ:はみ出し、グリッド折り返し、カードの高さ揃え
- C. タイポグラフィ:WCAG AA コントラスト、行長、見出し階層
- D. インタラクション要素:ボタン区別、エラー色依存(色覚多様性配慮)
- E. 画像・アイコン:アスペクト比、Hero 背景の表示確認
- F. モバイル固有:ハンバーガー出現、フォーム幅、テーブル横スクロール
- G. AI 感チェック:構造・コピー・配色のテンプレ感
特に効いたのが G. AI 感チェック だ。これは他のチェック項目と毛色が違う。コードや数値で判定できない、純粋に「見て感じる」しかない領域を言語化している。
**コピー・文言の質**(言語的なAI感)
- h1〜h2 レベルの見出しが、サービス名を入れ替えても別サービスに成立する汎用文言になっていないか
- 「すべての人に」「誰でも」「どこでも」など主語が抽象的すぎないか
- 「簡単に」「シンプルに」「直感的に」「スマートに」など中身のない副詞が多用されていないか
- 「業界最高水準」「信頼の〇〇」「選ばれ続ける理由」など根拠が示されない信頼訴求がないか
**レイアウト構造のパターン**(テンプレート的なAI感)
- H1 の直上に uppercase + letter-spacing のアイキャッチ文(eyebrow text)がないか
- 「なぜ選ばれるか」「主な機能」「メリット」「強み」系のセクションがないか(Why-choose-us パターン)
- アイコン+タイトル+短い説明文という同一構造のカードが3つ以上グリッド表示されていないか
- 企業ロゴを横並びにした「〜に掲載」「〜が信頼」系のロゴ帯がないか
**視覚的個性の欠如**(見た目のAI感)
- スクリーンショットを業界を知らない人に見せたとき、何のサービスか10秒で当てられるか
- 配色が「とりあえず青」「とりあえず紫グラデーション」などAIのデフォルト選択になっていないか
- ホバー時にふわっと浮き上がるカード・光るボーダーなど、派手さだけで目的のないインタラクションエフェクトがないか
これらは全部 コード上には現れない問題 だ。<h1> タグの上に <p class="eyebrow"> が入っていても、構文として何も間違っていない。型エラーも出ない。でも「サービス名を入れ替えても成立する汎用文言」かどうかは、画面を見ないとわからない。
Claude Code のマルチモーダル能力を最大限に使うべきポイントがここだった。「コードに落ちる前の判断」を画像経由でやってもらう。
code-review スキルから自動で呼び出す
最後のピースが、自動連携 だ。code-review スキルにこの記述を追加した。
## フロントエンドファイルが含まれる場合
`git diff --name-only HEAD` の結果に `site/src/` 配下の `.astro` / `.css` / `.ts`
ファイルが含まれている場合は、コードレビューの報告の後に `layout-check` スキルを
呼び出して視覚チェックも実施する。
これで「コードレビューして」と Claude Code に頼むと、フロントの変更があれば勝手に UI レビューまで回る。dev サーバが立っていなければ自動で立ち上げ、ポートを検出し、URL を組み立て、スクショを撮り、Read で読んで、レビューを書く。
人間側でやることは 「指摘の取捨選択」だけ になった。
自走ループが回るのが一番効いた
数字以上に効いたのが、ループの自走化だ。
これまでは
Claude が修正
↓
[人間] dev サーバ確認
↓
[人間] ブラウザ開いて 3 枚スクショ
↓
[人間] Claude に画像共有
↓
Claude がレビュー
↓
Claude が修正
↓
(また人間が 3 枚スクショ撮る)
これが、
Claude が修正
↓
Claude が layout-check 自動起動(dev サーバ起動含む)
↓
Claude が Playwright でスクショ撮影
↓
Claude が画像を Read してレビュー
↓
Claude が修正
↓
Claude が layout-check 自動起動
↓
...(人間を介さずループ)
になった。
5 分 × 3 ページ × 5 コミット = 75 分が、丸ごと 0 分になる。人間が起きたら「指摘が出揃ったので、取捨選択してマージしてください」の状態になっている。
これは Computer Use では実現しづらかった。Computer Use は 1 アクションごとに人間が監督する 設計に近く(推奨される使い方として「高インパクトのアクションは人間がループに入る」とされている)、改修 → レビュー → 改修の連続を任せるには向いていない。Playwright で固めて、Claude Code に UI レビューだけ任せるほうが、自走化との相性が良かった。
実際に検出された事例
このスキルを導入してから検出された事例をいくつか紹介する。全部「コードは正しい」変更だ。型エラーも構文エラーも、code-review スキルの指摘も出ていない。
タップターゲット違反(自動検出ロジックが拾った)
- ハンバーガーボタン w-9 → w-11(36px → 44px)
- 比較に追加・印刷・LINE 共有・X 共有・Google マップ ボタンに
min-h-[44px]追加 - 検索タブボタン py-2.5 → py-3 +
min-h-[44px] - 地図レイヤーボタン、CompareTray ボタン
min-h-[44px]追加
これらは layout-check.mjs の自動検出が CRITICAL として上げてきた。動的判定ロジックを入れていたおかげで、装飾用のアウトラインボタンは除外されていた。
AI 感 UI(マルチモーダルUI レビューが拾った)
- eyebrow text を削除:H1 の直上に「Disaster Risk Intelligence」という uppercase + letter-spacing の英語飾り文字が入っていた。Claude Code が「ランディングページのテンプレでよく見るパターンです」と指摘した
- セクション見出しの書き換え:「○○が選ばれる理由」というテンプレ的なセクションを「こんな場面で使えます」に変更。Why-choose-us パターンからユースケース訴求への転換
- CTA 文言の具体化:「今すぐ始める」のような汎用文言を「引越し先を比較する」「不動産購入前のチェック」など具体的な行動喚起に書き換え
これらは AI 感チェックの観点に沿った指摘で、全部スクショを見ないと出てこない。
モバイル崩れ
- 検索プレースホルダー切れ:デスクトップでは収まっていた長文プレースホルダーが、モバイル(390px)で右端にはみ出していた。短縮して解消
-
モバイルでだけフッターロゴが横に引き伸ばされて潰れた見た目に:デスクトップでは正常表示されていたフッターのロゴ画像が、モバイルのスクショで横方向に間延びして縦が潰れた表示になっていた。原因は flexbox 親要素の
align-items: stretchデフォルト挙動で、h-8 w-auto shrink-0指定の<Image>が親の高さに引き伸ばされ、それに合わせて横幅も歪んでいた。self-startを追加して解消。コードを見ても気付かないし、デスクトップ表示でも崩れない。モバイルのスクショを Claude Code が見て「ロゴのアスペクト比が崩れていて、本来の縦横比じゃなくなっています」と指摘した のがきっかけで気付けた典型例 -
logo-full.png のサイズ問題:
height={32}の指定を忘れていて、Astro が画像を巨大な WebP に変換していた。LCP が悪化していたが、これはネットワークタブで気付くタイプの問題で、Playwright + Claude Code の UI レビューの範囲外だった
タップ領域改善
- ロゴリンクに self-stretch:ヘッダーの全高をタップ領域にして、ヘッダー上部の余白部分もロゴクリックで反応するように
これらは全部「UI レビューを通したから出てきた」指摘だった。コードレビューだけでは絶対に出ないし、自分で画面を開いても気付かなかった。特にモバイル固有の崩れは、デスクトップ作業中の人間の目では絶対に検出されない。Playwright で違うビューポートのスクショを撮らせて Claude Code に Read させる構成は、ここに直接刺さる。
Computer Use と Playwright スクショ方式の住み分け
Computer Use を完全否定したいわけじゃない。用途を分けて考えると、選択は単純になる。
| 用途 | 適切なツール |
|---|---|
| 静的 UI レビュー(レイアウト・AI 感・モバイル崩れ) | Playwright + Claude Code(本記事の方式) |
| 動的インタラクション確認(フォーム送信・モーダル・遷移) | Computer Use / Playwright MCP |
| E2E 回帰テスト(PR ごと自動実行) | Playwright(純粋なテストコード) |
| 探索的 QA(壊れそうな導線探し) | Computer Use / Claude in Chrome |
判断軸はシンプルで、
- Claude に「操作させたい」用途 → Computer Use
- Claude に「見せて判断させたい」用途 → Playwright + Claude Code に Read させる
このどちらかで決まる。UI レビューは後者で十分だし、後者のほうが圧倒的に軽い・速い・安い。
学び・まとめ
- Claude にできるのはコードレビューだけじゃない。マルチモーダル能力を使えば、UI レビューも自動化できる
- 「Claude に操作させる」と「Claude に見せて判断させる」は別物。UI レビューは後者で十分で、後者のほうが軽い
- スクショ撮影は Playwright(無料・高速・決定的)、判断は Claude Code(マルチモーダル)に分けると、コスパが圧倒的に良い
- 個人開発でも実装コストは低い。
SKILL.mdと 100 行程度の Playwright スクリプト 1 本で済む - 自動連携(
code-review→layout-check)まで組むと、改修 → UI レビュー → 改修の自走ループが回るようになり、手動スクショの 75 分が消える - AI 感チェック観点は特に有用。コード上には現れない「テンプレ感」「汎用文言」を画像経由でレビューさせると、AI が書いた UI に AI 自身が「AI 感ある」とツッコめる
「AI が書いた UI を AI に UI レビューさせる」という構図、最初は皮肉に感じたが、回してみるとめちゃくちゃ実用的だった。AI で開発するなら、AI のマルチモーダル能力は最後まで使い切る。コードレビューで止めるのは、まだ AI を半分しか使っていない。
この記事は Zenn にも同じ内容を投稿しています。