Lv.02

初級編 工務店の3ページサイト

3ページ・手70%とAI30%で分ける

琥珀

琥珀からの依頼書

工務店の3ページサイトを作ってください。ヘッダーとフッターは3ページで同じものを使ってください。

色と余白はCSS変数にまとめ、クラス名はBEMで付けてください。

お知らせ一覧・施工事例のグリッド・フッターの3つはAIに書かせ、出てきたコードを自分で直してください。

カンプと配布物

HTMLカンプ3枚/PNG(1440・390)/完成ZIP/公開デモ

手で書くところ

BEM/CSSカスタムプロパティ/CSS Grid(auto-fill・minmax)/details要素のSPナビ/dl要素/相対パスの共通パーツ

AIに任せるところと検品

AIに書かせる:お知らせ一覧・施工事例グリッド・フッター/html-validate+Playwrightのスクショ比較

依頼を受けたところから

今回の相手は、藤沢市辻堂の工務店「木もれ日建築工房」さんです。1998年から地元で木造住宅を建てていて、社員は9人。頼まれたのは3ページ、トップと施工事例と会社概要です。依頼のうち大事なところは3つあります。ヘッダーとフッターは3ページで1文字も変えないこと色と余白はCSS変数に集めてクラス名はBEMで付けること、そして3つの部品はAIに書かせて、出てきたものを自分で直すこと。前の回とちがって、今回は書きはじめる前に「どこを自分の手でやって、どこをAIにやらせるか」を決めます。決めてから書くと、壊れたときに探す場所が半分になります。

完成するとこうなります。

完成したトップページ(1440px幅)

スマートフォンの幅ではこうなります。

完成したトップページ(390px幅)

この回で新しく出るもの

前の回でやったこと(リセットCSS・flexbox・<picture>・768pxのメディアクエリ)はそのまま使うので、ここでは説明しません。新しく出るのは次の10個だけです。

新しく出るもの何のために使うか
BEM(Block__Element--Modifier)クラス名を見ただけで、どの部品のどこか分かるようにする
CSSカスタムプロパティ(--*var()色・余白・角丸を1か所に集めて、あとから直せるようにする
display: grid行と列のある並びを組む
repeat(auto-fill, minmax(280px, 1fr))画面幅にあわせて列数をブラウザに決めさせる
<details> <summary>JavaScriptなしで開閉するSPのメニューを作る
<dl> <dt> <dd>「項目名と値」の組を、意味の合うタグで書く
<time datetime>日付を、人にも機械にも読める形で書く
相対パス(./3ページを行き来するリンクを、どこに置いても壊れない形にする
aria-current="page"いま見ているページがどれかを、見た目と支援技術の両方に伝える
Playwrightのスクショ比較自分の画面とカンプのずれを、目ではなく機械で見つける

Step 1 あとから直せる書き方に組み替える

前の回では、ナビのリンクをこう書きました。

css
.nav ul li a {
  font-size: 15px;
  color: #2e2a26;
}

読みやすい書き方です。ただ、困ることが2つあります。HTMLの入れ子を少しでも変えると、このセレクタは届かなくなります。そして #2e2a26 という色が、ファイルの何行目にあるのか探さないと分からない。ページが3枚になると、この2つがそのまま作業時間になって返ってきます。

そこで、色と余白と角丸を全部いちばん上に集めます。style.css の先頭はこうなります。

css
:root {
  --green: #2f4f3a;
  --wood:  #b8763e;
  --paper: #faf8f5;
  --line:  #e2ddd4;
  --ink:   #24282a;
  --ink-mid: #6b7169;
  --white: #ffffff;
  --space-section: 80px;
  --space-gutter: 24px;
  --radius: 4px;
  --w: 1080px;
}

--green のように2つのハイフンで始まる名前がカスタムプロパティ(CSSの中で使い回せる自前の変数)です。:root は文書のいちばん外側を指す書き方で、ここに置くとページのどこからでも var(--green) で呼び出せます。値を変えたいときに触るのは、この12行だけになります。

さきほどのリンクは、こう変わります。

css
.nav__link {
  font-size: 15px;
  padding-bottom: 4px;
  border-bottom: 2px solid transparent;
}

変わったのは2つです。セレクタが .nav ul li a から .nav__link になったので、HTMLの入れ子をどう変えてもこの指定は届きます。そして color が消えました。色はリセットCSSの a { color: inherit; } で本文の色を受け継いでいるので、書き直す必要がありません。書かずに済む指定は書かないほうが、あとで矛盾しません。

クラス名の付け方が BEM です。ブロック名__要素名--状態 の3つに分けます。nav がブロック(部品のかたまり)、__link がその中の要素、状態を分けたいときだけ -- を足します。このサイトで使うブロックは、この一覧から増やしません。

text
logo / nav / hero / reasons / reasons__item / flow / flow__step /
works / works__card / news / news__item / cta / company / contact / footer

__ は1回までです。works__card__title のように2回つなげると名前がすぐ長くなるので、works__title にします。

これは手で書く

ここは手で書きます。変数の名前とブロックの一覧は、このあとAIに渡す「守ってほしいこと」そのものだからです。自分で決めていないルールは、AIが守ったかどうかも判断できません。

ここまでで画面がこうなっていれば OK:style.css の先頭に :root があり、色の直書き(# で始まる値)がそこから下に1つも無い状態。

Step 2 3ページで同じヘッダーを使う

3ページで同じヘッダーを出す方法は、この回では同じHTMLを3枚に貼る、これだけです。1か所にまとめる仕組みはいくつもありますが、どれも道具の準備が要ります。今やるのは、貼ったものが本当に同じかを確かめる練習です。

ロゴは日本語と英字を縦2段にするので、<span> を2つ入れています。

html
<a class="logo" href="./index.html">
  <span class="logo__jp">木もれ日建築工房</span>
  <span class="logo__en">KOMOREBI KOUBOU</span>
</a>

リンク先が ./index.html になっているところが要点です。先頭の ./ は「いま自分がいるフォルダの中の」という意味の相対パスです。/index.html と書くと「サーバーのいちばん上から見た index.html」になり、フォルダごと別の場所に置いたときや、ファイルを直接開いたときに行き先を見失います。3ページを行き来するリンクは、全部そろえます。 先頭は必ず ./ です。

そして、いま開いているページのリンクにだけ、この属性を足します。

html
<li><a class="nav__link" href="./index.html" aria-current="page">トップ</a></li>

aria-current="page" は「このリンクは、いま見ているページです」という意味です。画面読み上げにそのまま伝わり、CSSの側からも属性セレクタで拾えます。

css
.nav__link[aria-current="page"] {
  border-bottom-color: var(--green);
  color: var(--green);
}

.nav__link--active のようなクラスを足しても見た目は同じになりますが、それだと画面を見ていない人には何も伝わりません。同じ手間で両方に伝わるほうを選びます。

ここまでで画面がこうなっていれば OK:3ページのヘッダーが同じ見た目で、いま開いているページのリンクにだけ緑の下線が出ている状態。

Step 3 ナビをPCとSPで出し分ける

スマートフォンの幅では、メニューを開閉式にします。JavaScriptは使いません。HTMLだけで開閉する <details><summary> があるからです。

ただ、実際に作って分かった落とし穴があります。<details> は、閉じているあいだ、中身をそもそも描画しません。 だから「1つの <details> を書いて、PC幅ではCSSで開いた状態に見せる」ができません。最初にそれをやろうとして open を付けたら、今度はSPでも開きっぱなしになり、閉じる練習にならなくなりました。

そこで、PC用とSP用を別々に持ちます

html
<!-- PC/SPでナビを出し分ける(よくある書き方)。detailsは閉じていると中身を描画しないため、PC用は別に<nav>で持つ -->
<nav class="nav-pc" aria-label="メインメニュー">
  <ul class="nav__list">
    <li><a class="nav__link" href="./index.html" aria-current="page">トップ</a></li>
    <li><a class="nav__link" href="./works.html">施工事例</a></li>
    <li><a class="nav__link" href="./company.html">会社概要・お問い合わせ</a></li>
  </ul>
</nav>
<details class="nav-sp">
  <summary class="nav__toggle">メニュー</summary>
  <ul class="nav__list">
    <li><a class="nav__link" href="./index.html" aria-current="page">トップ</a></li>
    <li><a class="nav__link" href="./works.html">施工事例</a></li>
    <li><a class="nav__link" href="./company.html">会社概要・お問い合わせ</a></li>
  </ul>
</details>

同じリンクが2か所に出てきます。気持ち悪く見えるかもしれませんが、これは実際によく使われる書き方です。CSSでは、どちらか片方だけを出します。

css
.nav-pc {
  display: block;
}

.nav-sp {
  display: none;
}

768px以下でこれを入れ替えます。

css
@media (max-width: 768px) {
  header {
    padding: 14px 16px;
    flex-wrap: wrap;
  }

  .nav-pc {
    display: none;
  }

  .nav-sp {
    display: block;
    order: 3;
    width: 100%;
  }

  .nav__toggle {
    display: flex;
    align-items: center;
    min-height: 44px;
    font-size: 14px;
    color: var(--green);
  }

  .nav-sp .nav__list {
    display: block;
  }

  .nav-sp .nav__list li {
    padding: 10px 0;
    border-top: 1px solid var(--line);
  }
}

min-height: 44px は指で押す場所の高さです。これより小さいと押しそこねます。order: 3 は、flex-wrap: wrap で折り返したヘッダーの中で、メニューを最後の行に送るための指定です。

「メニュー」を押すと、こう開きます。

スマートフォン幅でメニューを開いたところ

これは手で書く

出し分けは手で書きます。「同じものを2回書く」と「CSSだけで済ませる」のどちらが正しいかは、実際に開いて確かめないと決まらないからです。ここをAIに任せると <details open> が1つ出てきて、SPで開きっぱなしになっているのに気づかないまま先へ進みます。

ここまでで画面がこうなっていれば OK:PC幅ではリンク3つが横に並び、390px幅では「メニュー」の1行になって、押すと3つが縦に開く状態。

Step 4 仕事の流れを Grid で並べる

「ご相談から引き渡しまで」の4ステップは CSS Grid で並べます。flexbox が「並べたものが順に流れる」仕組みだったのに対し、Grid は先にを決めて、そこに中身を入れる仕組みです。列の数をはっきり決めたいときは Grid が素直に書けます。

HTMLは番号つきの手順なので <ol> です。1つ分だけ載せます。

html
<li class="flow__step">
  <p class="flow__num">01</p>
  <h3 class="flow__heading">相談</h3>
  <p class="flow__body">電話かメールでご連絡ください。事務所でも、ご自宅でも、現地でも伺います。費用はかかりません。</p>
  <p class="flow__time">目安:1〜2回</p>
</li>

CSSはこれだけです。

css
.flow__list {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: var(--space-gutter);
}

grid-template-columns が列の設計図で、repeat(4, 1fr) は「1fr の列を4つ」。fr余った幅を分け合う単位で、gap を引いた残りを分けてくれます(% だと gap のぶんの計算が要ります)。768px以下では1列に落とします。

css
.flow__list {
  grid-template-columns: 1fr;
}

ここまでで画面がこうなっていれば OK:PC幅で4つの手順が横一列に並び、それぞれの上に緑の線と茶色の数字がある状態。

Step 5 会社概要を dl で書く

会社概要は「屋号:木もれ日建築工房」「創業:1998年」のように、項目名と値の組が10行続きます。この形のために用意されているタグが <dl>(定義リスト)で、<dt> が項目名、<dd> が値です。10行のうち先頭3行だけ載せます。

html
<dl class="company__list">
  <div class="company__row"><dt>屋号</dt><dd>木もれ日建築工房</dd></div>
  <div class="company__row"><dt>所在地</dt><dd>神奈川県藤沢市辻堂0-0-0</dd></div>
  <div class="company__row"><dt>創業</dt><dd>1998年</dd></div>
</dl>

<dt><dd> の組を <div> で1つずつ包んでいます。HTML の仕様で認められている書き方で、こうしないと「1行ぶん」をCSSでまとめて扱えません。包んだので、.company__rowdisplay: flex を当てるだけで、項目名と値が左右に分かれます。ここは前の回でやった flexbox のままです。

<table> で書きたくなる形ですが、表は「行と列の両方に意味があるもの」のためのタグです。ここは列が2本あるだけで、縦に比べる意味がありません。見た目が表に見えることと、表であることは別です。

ここまでで画面がこうなっていれば OK:会社概要の10行が、左に茶色の項目名・右に値、行の間に細い線が入って並んでいる状態。

Step 6 AIに書かせる(1)お知らせ一覧

ここから、はじめてAIにコードを書かせます。渡すのは部品1つぶんで、ページ全部ではありません。部品1つなら、出てきたコードを全部読めるからです。読めない量を受け取ると、直すかどうかの判断ができなくなります。

AIに任せる

渡すプロンプト

text
工務店のWebサイトに置く「お知らせ」の一覧を、HTMLとCSSで書いてください。

【守ってほしいこと】
- クラス名は BEM。ブロック名は news にする(news / news__list / news__item / news__date / news__title)
- 日付は <time datetime="2026-08-28"> のように機械可読な属性を付け、表示は 2026.08.28 の形にする
- 各行はリンクにしない(詳細ページが無いため)
- 色・余白・角丸は下のCSS変数だけを使う。新しい色を足さない
- ライブラリを使わない。素のHTMLとCSSだけ
- PCでは「日付」と「タイトル」を横並び、768px以下では日付を上・タイトルを下の2段にする
- html-validate で error 0 になること

【いま使っているCSS変数】
:root {
  --green: #2f4f3a;
  --wood:  #b8763e;
  --paper: #faf8f5;
  --line:  #e2ddd4;
  --ink:   #24282a;
  --ink-mid: #6b7169;
  --space-section: 80px;
  --space-gutter: 24px;
  --radius: 4px;
  --w: 1080px;
}

【入れる中身(この5件だけ。増やさない)】
2026-08-28 辻堂の平屋が完成しました。9月に見学会を行います
2026-07-15 夏季休業のお知らせ(8月11日〜8月16日)
2026-06-02 大工を1名募集しています
2026-04-20 茅ヶ崎の店舗改装が引き渡しになりました
2026-03-11 木材の価格改定にともなう見積についてのご説明

【出力】
HTMLとCSSを別々のコードブロックで。説明は3行以内で。

疑うポイント

  • datetime の値が表示と食い違っていないか(2026.08.28datetime に入れているのは誤り)
  • 変数にない色(#333rgba())が混ざっていないか
  • 勝手に「もっと見る」ボタンやアイコンが足されていないか

出てきたコード

実際にこれを投げて返ってきたHTMLの、1件目です。

html
<li class="news__item">
  <time class="news__date" datetime="2026.08.28">2026.08.28</time>
  <p class="news__title">辻堂の平屋が完成しました。9月に見学会を行います</p>
</li>

そして、リストの下にこれが付いていました。

html
<a class="news__more" href="#">もっと見る</a>

何が問題か

日付の書き方が間違っています。 datetime="2026.08.28" になっていますが、datetime 属性は機械が読むための欄なので、2026-08-28 のハイフン区切りでなければ日付として認識されません。正しい形を例つきで書いたのに、表示の見た目に引きずられて両方をドットで揃えてしまったわけです。

もうひとつ、「もっと見る」が足されています。 行き先が無いので href="#" です。仕様には「5件で打ち切り。もっと見るは置かない」と書きました。AIは「お知らせ一覧といえば、もっと見るがあるもの」という一般的な形を持っていて、指示に無いものを足してきます。足されたものに気づくには、自分が何を頼んだかを覚えているしかありません。 これが、プロンプトを自分で書くことの実利です。

どう指示し直したか

コード全体を出し直させると、直っていた場所が壊れることがあります。食い違いだけを送り返します。

text
出してもらったコードが、こちらの仕様と食い違っています。
コード全体を出し直さず、変更が必要な差分だけを出してください。

【仕様】
「守ってほしいこと」に、datetime は 2026-08-28 の形と書きました。
「入れる中身」は5件だけで、増やさないと書きました。

【いま出ているもの】
<出てきたHTMLとCSSをそのまま貼る>

【食い違い】
- datetime は 2026-08-28 のはずが、2026.08.28 になっている
- 5件で打ち切りのはずが、「もっと見る」リンクが足されている

戻ってきた差分を当てて、news__title<p> から <span> に自分で直しました(<li> の中の1行なので、段落として区切る必要がありません)。採用したのがこれです。

html
<li class="news__item">
  <time class="news__date" datetime="2026-08-28">2026.08.28</time>
  <span class="news__title">辻堂の平屋が完成しました。9月に見学会を行います</span>
</li>

CSSのほうは、そのまま採用しました。1行を flexbox で横に分けて、768px以下で flex-direction: column にするだけです。前の回でやったことしか使っていません。

ここまでで画面がこうなっていれば OK:日付5件が茶色で左に揃い、タイトルが右に並び、行の間に線が入っている状態。

Step 7 AIに書かせる(2)施工事例のグリッド

2つめは施工事例のカードです。プロンプトの < > で囲んだところは自分で差し替えます。CSS変数は Step 1 の :root をそのまま、6件の中身は配布のカンプに載っている文言(地名・種別・見出し・本文・延床・竣工・工期)をそのまま貼ります。

AIに任せる

渡すプロンプト

text
工務店のWebサイトの「施工事例」一覧を、HTMLとCSSで書いてください。

【守ってほしいこと】
- クラス名は BEM。ブロック名は works(works / works__grid / works__card / works__thumb /
  works__meta / works__title / works__body / works__spec)
- グリッドは CSS Grid で、grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)) を使う
- メディアクエリで列数を指定しない(auto-fill に任せる)
- 画像は aspect-ratio: 3 / 2 と object-fit: cover で高さをそろえる
- 画像には width と height 属性を必ず入れる(読み込み時のガタつきを防ぐため)
- 色・余白・角丸は下のCSS変数だけを使う
- ライブラリを使わない。素のHTMLとCSSだけ
- html-validate で error 0 になること

【いま使っているCSS変数】
<部品①と同じ :root をそのまま貼る>

【1枚のカードに入れるもの(上から順)】
写真 / 地名・種別(例:藤沢市・新築)/ 見出し / 本文2行 / 規模3項目(延床・竣工・工期)

【入れる中身(6件)】
<カンプに載っている6件の表をそのまま貼る>

【出力】
HTMLとCSSを別々のコードブロックで。カードは6枚とも全部書いてください。説明は3行以内で。

疑うポイント

  • minmax の下限を勝手に変えていないか(280px 未満にすると3列で潰れる)
  • 画像の width / height が入っているか
  • 規模3項目が <dl> でも <ul> でもなく <div> の羅列になっていないか(意味のあるタグに直す)

出てきたコード

6枚とも返ってきました。1枚目だけ載せます。

html
<div class="works__card">
  <img class="works__thumb" src="images/work-01.webp" alt="松林に向かって開いた平屋">
  <p class="works__meta">藤沢市・新築</p>
  <h3 class="works__title">松林に向かって開いた平屋</h3>
  <p class="works__body">南側の松林に向けて大きく窓を取り、天井を屋根なりに上げました。夏は葉が日差しをさえぎります。</p>
  <div class="works__spec">
    <div>延床 92㎡</div>
    <div>竣工 2026年8月</div>
    <div>工期 6か月</div>
  </div>
</div>
css
.works__grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
  gap: 24px;
}

何が問題か

グリッドの下限が書き換わっています。 minmax(220px, 1fr) になっていますが、指定したのは minmax(280px, 1fr) でした。repeat(auto-fill, minmax(下限, 1fr)) は「下限より狭くならない範囲で、入るだけ列を作る」指定なので、中身が入る幅が1080pxのとき、下限280pxなら3列、220pxなら4列になります。4列だと1枚250px弱で、写真と3つの数字が潰れます。AIは数字をよく書き換えます。指定した数字は指定したとおりか、必ず見ます。

画像の大きさが書かれていません。 <img>widthheight の属性がありません。CSSに aspect-ratio: 3 / 2 があるので最終的な高さは揃いますが、CSSが読み込まれる前の一瞬、ブラウザは画像の大きさを知りません。属性で書いておくと、その一瞬でも場所を空けて待つので、読み込みの途中でページがガタッと動きません。

規模3項目の書き方が合っていません。 「延床」「竣工」「工期」は項目名と値の組なので、<div> の羅列ではなく、Step 5 と同じ <dl> が合います。

どう指示し直したか

さきほどと同じ形で送り返しました。頭の2行と【いま出ているもの】は同じなので、変わるところだけ載せます。

text
【仕様】
「守ってほしいこと」に、minmax(280px, 1fr) を使うこと、
img に width と height を入れること、規模3項目は意味のあるタグにすることを書きました。

【食い違い】
- minmax の下限は 280px のはずが、220px になっている
- img に width / height 属性が入っているはずが、入っていない
- 規模3項目は意味のあるタグのはずが、div の羅列になっている

ただし、戻ってきた差分をそのまま当ててはいません。 <dt> に数値、<dd> にラベルが入っていて上下が逆でした。項目名が <dt>、値が <dd> です。ここだけ自分で組み替えました。

html
<dl class="works__spec">
  <div><dt>延床</dt><dd>92㎡</dd></div>
  <div><dt>竣工</dt><dd>2026年8月</dd></div>
  <div><dt>工期</dt><dd>6か月</dd></div>
</dl>
css
.works__grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
  gap: var(--space-gutter);
}

.works__thumb {
  width: 100%;
  aspect-ratio: 3 / 2;
  object-fit: cover;
}

auto-fill にしておくと、768px以下のためのメディアクエリを書かなくても勝手に1列になります。 カードが3枚のトップページでも、6枚の施工事例ページでも、同じCSSがそのまま使えます。

補足

2回とも、AIは「まちがえた」というより「よくある形に寄せた」だけです。よくある形が多数派なのは、それが多くの場合ちょうどいいからで、今回のように仕様のほうが具体的なときだけ食い違います。だから直すのは3か所で済みます。書き直しではなく、突き合わせです。大丈夫、まだ間に合います。

ここまでで画面がこうなっていれば OK:PC幅でカードが3列に並び、写真の高さが全部そろい、390px幅では1列に落ちている状態。

Step 8 AIに書かせる(3)フッター

最後はフッターです。これは3ページに同じものを貼る部品なので、プロンプトにもそう書きます。

AIに任せる

渡すプロンプト

text
工務店のWebサイトの共通フッターを、HTMLとCSSで書いてください。

【守ってほしいこと】
- クラス名は BEM。ブロック名は footer
- PCでは3カラム、768px以下では1カラムに縦積み
- 3ページ(index.html / works.html / company.html)で同じものを貼り付けて使う。
  ページごとに変わる部分を作らない
- サイト内リンクは相対パス(./index.html の形)
- 電話番号は tel: リンク、メールは mailto: リンクにする
- 色・余白は下のCSS変数だけを使う
- html-validate で error 0 になること

【いま使っているCSS変数】
<部品①と同じ :root をそのまま貼る>

【入れる中身】
<カンプに載っている3カラム分の文言をそのまま貼る>

【出力】
HTMLとCSSを別々のコードブロックで。説明は3行以内で。

疑うポイント

  • サイト内リンクが絶対パス(/index.html)になっていないか。ファイルを直接開くと壊れる
  • 3ページに貼ったとき、1文字でも違いが出ていないか(差分を取って確かめる)
  • <nav>aria-label が付いているか(ヘッダーのナビと2つになるため)

出てきたコード

2列目のリンクだけ載せます。

html
<nav class="footer__col">
  <ul>
    <li><a href="/index.html">トップ</a></li>
    <li><a href="/works.html">施工事例</a></li>
    <li><a href="/company.html">会社概要・お問い合わせ</a></li>
  </ul>
</nav>

何が問題か

サイト内リンクが絶対パスです。 /index.html になっています。プロンプトに「相対パス(./index.html の形)」と明記したのに、先頭のドットが落ちました。Step 2 と同じ問題で、ファイルをそのまま開くと行き先を見失います。疑うポイントの1つ目にこれを書いたのは、同じ間違いが起きると前もって分かっていたからです。「疑うポイント」は、そのまま自分の目のチェックリストになります。

2つ目のナビに名前がありません。 <nav>aria-label が付いていません。このページには <nav> がヘッダーとフッターの2つあります。画面読み上げを使う人には「ナビゲーション」が2つ並ぶだけで、どちらがどちらか分かりません。名前を付けます。

html
<nav class="footer__col" aria-label="サイト内リンク">
  <ul>
    <li><a href="./index.html">トップ</a></li>
    <li><a href="./works.html">施工事例</a></li>
    <li><a href="./company.html">会社概要・お問い合わせ</a></li>
  </ul>
</nav>

ヘッダー側は aria-label="メインメニュー" です。この2つが違う名前になっていれば区別が付きます。CSSは3カラムの flexbox に flex-wrap: wrap を足しただけで、最下段の注記に width: 100% を当てて次の行へ送っています。

直したフッターを3ページに貼ったら、本当に同じか確かめます。目で見比べません。

bash
diff index.html works.html

<footer> から下の行が差分に出てこなければ、1文字も違っていません。タイトルやナビの aria-current は当然ちがうので、そこは差分に出ます。

ここまでで画面がこうなっていれば OK:3ページのいちばん下に同じフッターがあり、390px幅では3つのかたまりが縦に積まれている状態。

Step 9 検品する

この回で新しく足す検品は1つです。自分の画面とカンプを、機械で重ねます。 Live Server でページを開いた状態のまま、別のターミナルで撮影します。

検品

bash
npx -y playwright screenshot --viewport-size=1440,900 --full-page http://127.0.0.1:5500/index.html shots/mine.png

合格の見え方shots/mine.png ができる。これと配布の comp/02-works.png を、ZIPに入っている compare.html にドラッグして2枚重ねる。重ねたとき、白く浮かび上がるのが文字のにじみだけになっていれば合格。ブロックの位置がずれていると、四角い白い帯が出る。

compare.html は2枚を mix-blend-mode: difference で重ねています。「同じ色のところを黒く、ちがう色のところを明るく」表示する重ね方です。ぴったり合っていれば画面はほぼ真っ黒になり、ずれているところだけが光ります。目で見比べると10pxのずれは見逃しますが、この方法なら光るので分かります。

前の回からの累積は、3ページぶんまとめてかけます。

検品

bash
npx -y html-validate index.html works.html company.html

合格の見え方:何も表示されずに入力待ちに戻る。1ページでもエラーがあれば、ファイル名と行番号が出る。

残りはコマンド1つと、目で3つです。まず、色の直書きが :root の外に残っていないかを見ます。

bash
grep -n "#[0-9a-f]\{3,6\}" style.css

出てきた行番号が全部 :root の中(先頭の十数行)なら合格です。それより下に出てきたら、その色は変数にし忘れています。

目で見るのは、390px幅でメニューを開いていない状態でもページの中身が全部読めること<details> が閉じていても本文は関係ありません。ここが消えていたら直します)、いま開いているページのナビにだけ緑の下線が出ていること3ページを相対パスだけで行き来できることの3つです。

ここまでで画面がこうなっていれば OK:検品コマンドが2つとも静かに終わり、重ねた画像が文字のにじみ以外は黒い状態。

次の回へ

次は縦長1ページの告知ページを作ります。手とAIの比率は半分ずつになり、AIには「PC版のCSSを渡してスマホ版を起こさせる」という、部品より一段大きい仕事を頼みます。

検品も1つ増えます。今度は自分の目ではなく、Lighthouse という測定ツールに点数を付けさせて、その指摘をつぶすところまでやります。

もっと聞きたいことがあれば、琥珀の公式LINEで質問できます。

琥珀の公式LINEで質問する(無料)