Responsive Overflow Guard
スマホ表示崩れ(横スクロール溢れ・要素の左寄せ/中央ズレ)は、ユーザー指摘を待たず完了宣言前に自分で潰す。 目視は信用しない(後述の500px頭打ち)。機械検出を必ず通す。
Procedure
- 静的検査(ゼロ依存・最優先): プロジェクトに
scripts/lint-layout.mjs系があれば実行。なければsrcを grep:- フットガン:
className="grid ..."にsm|md|lg|xl:grid-cols-Nがあるのに base のgrid-cols-Nが無い → モバイルで暗黙の単一auto列になり、max-content までコンテナ幅を無視して横溢れ。grid-cols-1(=minmax(0,1fr))を足す。
- フットガン:
- 実ビューポート検査(grid以外=ナビ左寄せ等も拾う): dev/preview を起動し、Playwright MCP(
browser_resize→setViewportSize)で真の幅 320/360/390/414 を再現。document.documentElement.scrollWidth <= clientWidth + 1を確認(超えたら溢れ)。- 溢れたら
getBoundingClientRect().right > clientWidthの要素を列挙→祖先を辿りgridTemplateColumns/display/min-widthを見て犯人特定(推測でCSSをいじらない)。
- 認証ゲートでローカルに入れない画面:
_始まり以外の一時ルートに同一マークアップ+実数値を置いて再現(_始まりはNext.jsのprivate folderで404)。済んだら削除。 - 直したら 2 を再実行し scrollWidth==clientWidth・溢れ0 を確認してから完了宣言。
Pitfalls
- ブラウザのウィンドウ縮小(
resize_window/devtoolsresize_page)は ~500px で頭打ち。320/390 指定しても実際は500pxで描画され、狭幅でしか出ない溢れを見逃す。真の狭幅は Playwright MCP の viewport か CDP device emulation でしか出せない。 - 「ビルド成功」「CSSに新クラスが乗った」≠「スマホで崩れてない」。実幅で scrollWidth を測るまで完了と言わない。
.btn(=inline-flex)なタブ/ボタンをflex-1セルに置くと中身がセル左端に寄る → リンク側にflex w-fullを付けて中央化。- レイアウト変更で新たな溢れを作り込むことがある(横並び化で max-content 増→暗黙auto列が溢れた実例)。変更後は必ず再検査。
Verification
- 静的検査 PASS(grid に base 列指定あり)
- 真の 320/360/390px で
scrollWidth <= clientWidth(溢れ0) - 下ナビ等の主要要素がセル内で中央寄せ(
rect中心が一致) - デプロイ後ライブURLでも本番JS/CSSに修正が反映()