Lv.06

上級編 藤沢の製作所の企業サイト

6ページ・構成からAIに任せて、公開まで

琥珀

琥珀からの依頼書

製作所の企業サイトを6ページで作り、Cloudflare Pages に公開してください。

構成案はAIに2つ出させ、どちらを採用するかはあなたが決めてください。

公開したあと、GA4のリアルタイムに自分のアクセスが1回だけ届くところまで確認してください。

カンプと配布物

6ページ分のHTMLカンプ/PNG(1440・390)/完成ZIP/公開デモ

手で書くところ

指示書を書く(サイトマップ・ページ要件・制約)/AIの構成案2つから採否を決める/コミットメッセージ/修正指示

AIに任せるところと検品

AIに書かせる:6ページのHTML・CSS・フォーム・404・robots.txt・sitemap.xml・canonical・JSON-LD/+Git・Cloudflare Pages・GA4リアルタイム・リンク切れ0

依頼を受けたところから

依頼主は、藤沢で板金と装置を作っている製作所です。ボクが依頼書を噛み砕くと、やることは3つに割れます。6ページの企業サイトを作ることその構成をAIに2案出させて、どちらを採るかは自分が決めること公開して、GA4(サイトに来た人を数える道具)のリアルタイムに自分のアクセスが1回だけ届くのを確かめること。前の5回は「作れたら終わり」でした。この回は、インターネットに置いて、人が来たことを数えられる状態までが完成です。

手で書くのは10%です。残りの90%は、構成の設計からAIに任せます。あなたの仕事は、渡す前に指示を書くことと、返ってきたものを疑って直させることの2つだけになります。

完成した企業サイトのトップを、幅1440pxで上から下まで写したもの

スマホ幅(390px)だと、こうなります。3列が1列に落ち、ヘッダーのナビは開閉式に変わります。

同じトップを幅390pxで写したもの。3列だったカードが1列に積まれている

下層の5ページは、6ページとも同じ型です。事業内容ページを1440pxで見ると、パンくず・見出し・表・末尾CTA・フッターの並びが、トップと同じ骨格の上に乗っているのが分かります。

事業内容ページを幅1440pxで写したもの。パンくずの下に見出しと表が3つ並んでいる

この回で前提にしているのは 01 から 05 の全部です。セマンティックHTML・flexbox・BEM・CSSカスタムプロパティ・CSS Grid・clamp()・モバイルファースト・<details> のスマホナビは、説明せずにそのまま使います。忘れていたら、その回に戻ってから来てください。

ここまでで OK:依頼書の3つを、自分の言葉で言い直せる状態。

この回で新しく出るもの

新しいのは、この10個です。半分は「コードの書き方」ではなく「サイトを世に出すときの作法」です。

ひとことで言うとどこで使うか
構成からAIに任せる何ページ作るか・何を載せるかの相談から始める指示書とプロンプト
共通部品の同一性ヘッダーとフッターが6ページで1文字も違わないこと全ページ
パンくずいまサイトのどこにいるかを示す道しるべトップ以外の5ページ
404.html存在しないURLを開いた人に出すページ公開したあとに効く
robots.txt検索エンジンに「このサイトの案内図はここ」と伝える1枚サイトの一番上の階層
sitemap.xml見てほしいページのURLを並べた案内図同上
canonical「このページの正式なURLはこれ」と宣言する1行各ページの <head>
JSON-LD の使い分けトップは会社そのもの、下層は道しるべを機械向けに書くOrganizationBreadcrumbList
Gitいつ何を変えたかを、あとから読める形で残す仕組み手元のフォルダ
Cloudflare Pages / GA4作ったフォルダを公開する場所と、来た人を数える道具公開のあと

検品はこの回で6つ目が足されます。Git・公開・GA4 です。コマンドで白黒がつくものと、公開したURLを自分で開いて確かめるものが混ざります。

ここまでで OK:この10個のうち、名前を知らないものがどれか分かった状態。

指示書を1枚書く

これは手で書く

この回で手を動かすのは、ほぼこの1枚だけです。指示書が薄いと、出てくるコードも薄くなります。 ここを人に書いてもらうと、この回は学ぶことが何も残りません。

いままでは、こちらがカンプ(完成見本)を持っていました。今回は持っていません。代わりに持つのが、この1枚です。ボクが実際に書いたものを、そのまま出します。

text
【会社】株式会社ミナモ製作所(架空)
【業種】精密板金の受託加工/省人化装置の設計・製作/既存設備の改造・修理
【所在】神奈川県藤沢市桐原町0-0-0
【目的】問い合わせを1件でも増やす。特に「図面が無い・1個だけ」の相談
【ページ】6ページ(トップ/事業内容/製作実績/会社概要/採用情報/お問い合わせ)
【使う技術】素のHTML・CSS・JavaScript。ビルドツール・フレームワーク・CSSライブラリを使わない
【クラス命名】BEM風(ブロック名は英小文字とハイフン。例:.works-card__title)
【色】#143d6b(主)/#5b7c99(副)/#ffffff(地)/#f4f7fa(薄い面)/#d8e0e8(罫線)
【書体】Noto Sans JP(日本語)/Inter(英字・数字)
【禁止】絵文字・グラデーション・box-shadow・アイコンフォント・外部JSライブラリ
【レスポンシブ】モバイルファースト。ブレークポイントは 600px と 1024px の2つだけ
【上限】1ページの転送量 1.5MB 以内。画像は WebP
【検品】html-validate error 0/リンク切れ 0

13行しかありません。大事なのは中身の濃さではなく、種類が揃っていることです。上から順に、誰の・何の・どこの話かが3行、作るものの範囲が2行、技術と見た目の縛りが5行、そして最後の3行が合否の決め方です。

とくに効くのは下の3行です。【禁止】は、書かないと必ず足されます。AIは「よく見るWebサイトらしさ」を出そうとするので、影とグラデーションと絵文字が勝手に入ります。【上限】は、画像を大きいまま貼られるのを止めます。【検品】は、合格の条件を渡す側が先に決めているという宣言です。これが無いと、AIは「動きました」で終わりにします。

「いい感じの会社サイトを6ページで作って」と何が違うのか。違うのは、あとで文句を言える場所があるかどうかです。禁止と書いてある影が入っていたら、それは仕様との食い違いです。書いていなければ、それはただの好みの話になって、直させる根拠がありません。

指示書は、AIのためというより自分のために書きます。書き終わったとき、あなたはもうこのサイトの合否を判定できる人になっています。

ここまでで OK:13行の指示書が自分のフォルダに1枚あり、【検品】の行に自分で決めた条件が書かれている状態。

AIに書かせる①:構成を2案出させる

まだコードは書かせません。何ページ作って、それぞれに何を載せるかを先に相談します。

AIに任せる

渡すプロンプト

text
下の事業について、Webサイトの構成案を2つ出してください。コードはまだ書かないでください。

【事業の情報】
<さっき書いた13行の指示書を、そのまま貼る>

【条件】
- 6ページ。トップを含む
- 素のHTML/CSS/JavaScript。ビルドツールは使わない
- 目的は「問い合わせ」。1ページ目からそこへ向かう導線を作る

【出力】
案ごとに、次の表を出す。案の最後に「この案が向いているのはどういう場合か」を2行で。
| ページ名 | URL | このページの目的 | 載せる要素(上から順) | 次にどこへ送るか |

疑うポイント

  • 2案が実質同じなら、「違う軸で出し直して」と言う
  • ページ数を勝手に増やしていないか
  • 書く材料が無いページ(よくある質問・ブログ・お客様の声)が混ざっていないか。材料が無いページは削る

「2つ出して」と書くのは、比べる相手を作るためです。1案しか無いと、良し悪しではなく「これでいいか」で決めることになります。返ってきたのは、事業から考えた案と、お客さんの困りごとから考えた案でした。

案A:事業を起点にした構成

ページ名URLこのページの目的次にどこへ送るか
トップindex.html何ができる会社かを30秒で伝える事業内容・お問い合わせ
事業内容services.html3事業の詳細と受けられる範囲製作実績・お問い合わせ
製作実績works.html実際に作ったものを見せるお問い合わせ
会社概要company.html基本情報と設備採用・お問い合わせ
採用情報recruit.html募集要項採用メール
お問い合わせcontact.html連絡手段を渡す

AIが付けた「この案が向いているのは」は、「まず何ができる会社か」を一番気にする人が多い場合でした。事業内容が独立しているので、検索からそこへ直接来ても話が完結する、という理由です。

案B:困りごとを起点にした構成

ページ名URLこのページの目的次にどこへ送るか
トップindex.html「図面が無い・1個だけ」に刺さる訴求相談する
相談できることconsult.html課題別(図面が無い/1個だけ/古い設備)に整理製作実績
製作実績works.html実績お問い合わせ
会社についてabout.html会社概要と設備と採用を1ページに統合お問い合わせ
よくある質問faq.html見積・納期・支払いの不安を解消お問い合わせ
お問い合わせcontact.html連絡手段

こちらは「何を頼めるか分からない」不安の解消を優先したい場合、と書かれていました。ページ数はどちらも6で、勝手には増えていません。疑うポイントの2つ目は問題なしです。

採否を自分で決める

やることは3手順です。①2案を並べて違いを数える ②この事業の材料で埋められるものだけを採る ③採らなかった理由を1行ずつ書く。 ボクの結論はこうなりました。

判断対象理由
採用案Aの6ページ構成6ページとも、指示書に材料がある
不採用案Bの「よくある質問」納期日数・見積の目安・支払い条件が手元に無い。書けば中身のないページになる
不採用案Bの「会社について」への統合採用情報は「工場見学だけでも構いません」という別の温度感の呼びかけを持つ。会社概要と混ぜると埋もれる
保留案Bの「課題起点の言い方」ページは作らないが、トップの見出しに考え方だけ借りる

疑うポイントの3つ目に、そのまま引っかかったのが「よくある質問」です。 材料が無いのに枠だけ作ると、公開したあとに「準備中」と書かれたページが残ります。これは検索エンジンにも人にも良いことが1つもありません。

理由を1行ずつ書くのは、あとで自分が揺れないためです。3か月後に「やっぱりFAQを足そうか」と思ったとき、この1行があれば「材料が集まったのか?」から考え直せます。

ここまでで OK:採用する6ページの表が手元にあり、採らなかった案の理由が1行ずつ書けている状態。

AIに書かせる②:6ページのHTMLとCSS

構成が決まったので、ここからコードです。1回のやりとりで2ページまでにします。6ページを一度に頼むと、後半が雑になり、しかも自分が読み切れません。

AIに任せる

渡すプロンプト

text
下の構成で、Webサイトを作ってください。

【構成】
<採用した6ページの表をそのまま貼る>

【各ページの中身】
<載せる文言をそのまま貼る。ページごとに分けて渡す(1回のやりとりで2ページまで)>

【守ってほしいこと】
<13行の指示書をそのまま貼る>
- ヘッダー・フッター・パンくずは6ページで完全に同じにする
- CSSは1ファイル(style.css)。ページごとに分けない
- 現在地のナビには aria-current="page" を付ける
- 表は共通のクラス(.table)を使い、横に長い表は overflow-x: auto の親で包む
- 画像は width と height 属性を必ず入れる。1枚目以外は loading="lazy"
- html-validate で error 0 になること

【出力】
ページごとにコードブロックを分ける。CSSは最後にまとめて1つ。

疑うポイント

  • 6ページのヘッダー・フッターが1文字でも違っていないかdiff を取る)
  • CSSに、変数から外れた色の直書きが入っていないか
  • 「よくある質問」など、渡していないセクションが足されていないか

返ってきたヘッダーはこの形でした。6ページとも、これと同じ文字列が入っています。

html
<header class="site-header">
  <div class="site-header__inner">
    <a class="logo" href="index.html">
      <span class="logo__mark" aria-hidden="true"></span>
      <span class="logo__text">
        <span class="logo__jp">ミナモ製作所</span>
        <span class="logo__en">MINAMO WORKS</span>
      </span>
    </a>
    <nav class="nav" aria-label="サイト内">
      <ul class="nav__list">
        <li><a href="services.html" aria-current="page">事業内容</a></li>
        <li><a href="works.html">製作実績</a></li>
        <li><a href="company.html">会社概要</a></li>
        <li><a href="recruit.html">採用情報</a></li>
        <li><a href="contact.html">お問い合わせ</a></li>
      </ul>
    </nav>

6ページで違ってよいのは aria-current="page" の位置だけです。これは「いまあなたが見ているのはこのページです」を機械に伝える属性で、CSSはこれを目印に下線を引いています。

css
.nav__list a[aria-current="page"],
.nav-details__list a[aria-current="page"] {
  color: var(--navy);
  text-decoration: underline;
  text-decoration-color: var(--sub);
}

現在地の色分けをJavaScriptでやらないのは、JSが動かない環境でも現在地が分かるようにするためです。02で覚えた「HTMLでできることはHTMLでやる」の続きです。

ここを疑って直した

疑うポイントの1つ目、ヘッダーの diff(2つのファイルの違いを機械に出させる作業)から始めました。 案の定、6ページのヘッダーはずれていました。ずれは3か所です。

どこどうなっていたか
1ページナビ5項目の並び順が、ほかの5ページと違っていた
2ページ現在地に aria-current="page" が付いていなかった
CSS 1か所.stat__number の色が #16406e。指示書に無い、紺色の別の値だった

原因は単純で、AIはページごとにヘッダーを書き起こしているからです。人がコピペを繰り返すのと同じことが起きます。「同じにして」と頼んでも、6回書けば6回とも同じにはなりません。

直し方は2つあります。1つは、ずれた3か所を直すこと。もう1つは、同じものが必ず同じ文字列になる作り方に変えることです。今回は後者にしました。ヘッダー・フッター・パンくずを型として1か所に置き、6ページへ流し込んでから最終稿を書き出しています。前者だけだと、次にページを1枚足したときに同じずれが戻ってきます。

疑うポイントの3つ目にも、1件当たりました。company.html に、渡していない「代表挨拶」のセクションが足されていました。 会社概要のページに代表挨拶があるのは、たしかによくある形です。ただし中身は、役職名も名前も人数もAIが作った文章でした。指示書にも渡した文言にも無いので、削っています。

AIが足すものには2種類あります。 「言われていないが、あった方がいいもの」と、「それらしく見せるために作った事実」です。前者は採ってよく、後者は必ず捨てます。見分け方は1つで、その数字や名前がどこから来たかを、自分が言えるかどうかです。

390px で横に伸びた

最後の1つは、見た目では気づきにくいものでした。スマホ幅(390px)で製作実績のページを開くと、画面が横に少しだけ動きます。指で払うと右に空白が出る、あの状態です。

測ると、ページの中身の幅が 498px ありました。画面は390pxなので、108px はみ出しています。原因を探す場所は、はみ出している要素です。

css
.works-card {
  /* CSS Grid の子は既定で min-width:auto のため、中の表(.table 最小幅480px)が
     はみ出したままページ全体を横に広げてしまう。0 にして .table-wrap の
     overflow-x:auto に横スクロールの処理を任せる(390px実測で確認済み) */
  min-width: 0;
}

犯人はCSS Grid の初期値でした。Grid の子要素は、既定で min-width: auto、つまり「中身より小さくならない」という設定になっています。実績カードの中には最小幅480pxの表が入っているので、カードは480pxより小さくなることを拒み、そのままページ全体を押し広げます。min-width: 0 を足すと、カードは画面幅まで縮んでよくなり、はみ出した表は .table-wrapoverflow-x: auto が引き受けます。表だけが横にスクロールし、ページ本体は動きません。

この1行を足したあと、6ページと404ページの7枚とも、390px幅での中身の幅が390pxになりました。「なんとなく横に動く」は必ず理由があります。 数字で測れば、どの要素が何px はみ出しているかまで出ます。

ここまでで画面がこうなっていれば OK:6ページのヘッダーとフッターが完全に同じで、390px幅で横に払っても画面が動かない状態。

AIに書かせる③:フォームと404ページ

お問い合わせフォームと、存在しないURLを開いた人に出すページを作ります。

AIに任せる

渡すプロンプト

text
お問い合わせフォームと、404ページを作ってください。

【守ってほしいこと】
- フォームは送信しない。submit を preventDefault() して、完了メッセージに差し替える
- 完了メッセージの下に小さく「これは練習用のページです。実際には送信されていません。」と出す
- 入力欄には label を必ず紐づけ、required / autocomplete / inputmode を適切に付ける
- 送信ボタンは Enter キーでも押せる
- 404ページには <meta name="robots" content="noindex"> を入れる
- ライブラリを使わない
- html-validate で error 0 になること

【フォームの項目】
<会社名・お名前・メールアドレス・電話番号・ご用件・内容の表をそのまま貼る>

【404ページの中身】
<見出しと本文とリンクの実文をそのまま貼る>

【出力】
contact.html のフォーム部分・404.html・共通CSS・JavaScript の順に、別々のコードブロックで。

疑うポイント

  • action に架空のURLが入っていないか(入っていたら消す。本当に送信されると困る)
  • select の初期値が「選択してください」になっていて、required が効くか
  • 完了メッセージにフォーカスが移るか(画面読み上げの人に伝わらないため)

3つとも当たりました。疑うポイントは、当たったから価値があるのではありません。見る場所を先に決めていたから、10秒で確かめられたのが価値です。

1つ目。 返ってきた <form>action="/api/contact" が入っていました。そんな受け取り先はどこにもありません。このまま公開すると、送信ボタンを押した人にエラー画面が出ます。action ごと消しました。

2つ目。 ご用件の <select> の初期値が <option value="sheet" selected> になっていました。つまり「精密板金の見積」が最初から選ばれた状態です。これだと required を書いても意味がありません(すでに何か選ばれているので)。直したのがこの1行です。

html
        <option value="" selected disabled>選択してください</option>

value="" で中身を空にし、disabled で選び直せなくしてあります。これで required が効き、選ばずに送ろうとするとブラウザが止めてくれます。

3つ目。 送信したあとのフォーカス(いまキーボードの入力を受けている場所)が、どこにも移っていませんでした。目で見ている人には完了メッセージが見えますが、画面読み上げソフトを使っている人には何も起きていないのと同じです。足したのは2行です。

js
(function () {
  var form = document.getElementById("contact-form");
  var done = document.getElementById("contact-form-done");
  if (!form || !done) {
    return;
  }

  form.addEventListener("submit", function (event) {
    event.preventDefault();
    form.hidden = true;
    done.hidden = false;
    done.focus();
  });
})();

done.focus() が効くように、HTML側の完了メッセージには tabindex="-1" を振ってあります。

html
  <div class="contact-form__done" id="contact-form-done" tabindex="-1" hidden>
    <h2 class="contact-form__done-title">お問い合わせを受け付けました</h2>
    <p>2営業日以内にご返信します。お急ぎの場合は 0466-00-0000 までお電話ください。</p>
    <p class="contact-form__done-note">これは練習用のページです。実際には送信されていません。</p>
  </div>

tabindex="-1" は「Tabキーでは止まらないが、JavaScriptからならフォーカスを当てられる」という印です。見出しや段落は本来フォーカスを受け取らないので、この1語が要ります。送信して、完了メッセージに切り替わり、フォーカスがそこへ移るところまで、実際に動かして確かめました。ブラウザのConsole(JSのエラーが出る場所)にも何も出ていません。

お問い合わせページを幅390pxで写したもの。連絡先の表の下にフォームが並んでいる

404ページのほうは、<meta name="robots" content="noindex"> が最初から入っていました。これは「このページは検索結果に出さなくていい」という指定です。あわせて、このページだけは sitemap.xml に載せません。案内図に「見つかりませんでした」のページを載せる意味がないからです。

ここまでで画面がこうなっていれば OK:空のまま送信するとブラウザに止められ、全部埋めて送信すると完了メッセージに切り替わる状態。

AIに書かせる④:公開前の総点検

コードが揃ったので、公開する前に見落としを洗い出させます。ここではコードを出させません。

AIに任せる

渡すプロンプト

text
公開直前のサイトです。下のファイル一覧とHTMLを見て、公開前に直すべきものを洗い出してください。
コードは出さず、チェックリストの形で出してください。

【見てほしい項目】
- title / meta description / canonical が全ページにあり、ページごとに違うか
- OGP 4点(og:title / og:description / og:image / og:url)
- リンク切れ・相対パスの間違い
- 画像の alt
- robots.txt の Sitemap 行、sitemap.xml に載っているURL(404 が入っていないか)
- 本番に置いてはいけないもの(テスト用のテキスト、コメントアウトした古いコード、console.log)

【ファイル一覧】
<ls -R の結果を貼る>

【HTML】
<6ページ分を貼る>

【出力】
| 項目 | 状態(OK / 要修正) | 該当ファイル | 直す内容 |

疑うポイント

  • 「OK」が並んでいても、自分でブラウザのソースを1ページだけ開いて確かめる
  • AIはファイルの中身しか見ていない。公開したURLで開いたときの挙動は別
  • console.log は自分でも grep -rn "console.log" . して二重に確認する

返ってきた表です。

項目状態該当ファイル直す内容
title / description / canonical が別々かOK全7ページ
OGP 4点OK全7ページ
リンク切れ・相対パスOK
画像の alt要修正works.html実績カードの alt が見出しのコピーになっている
robots.txt の Sitemap 行OKrobots.txt
sitemap.xml に載っているURL要確認sitemap.xml404.html が入っていないか確認すること
本番に置いてはいけないものOK全7ページ

要修正は1件でした。works.html を自分で開いて見ると、たしかに実績カードの alt(画像が表示できないときに読まれる文)が、すぐ下の見出しとほぼ同じ文字列でした。

text
(直す前)alt="食品機械用の外装カバー"     ← 下の <h2> と同じ
(直した後)alt="溶接跡を平らに仕上げたステンレス製の外装カバー"

見出しの真上に同じ文が入っていると、読み上げソフトでは同じ言葉が2回続けて読まれます。 alt に書くのは、見出しの繰り返しではなく写真そのものの説明です。

「要確認」と書かれた sitemap.xml は、自分で確かめます。grep 404 sitemap.xml の結果は0件で、最初から入っていませんでした。console.log も自分で数え直して0件です。AIが「OK」と書いた項目まで自分で見に行くかどうかが、この検品の分かれ目になります。 AIが見ているのはファイルの中身だけで、公開したURLで実際に何が起きるかは見ていません。

内部のリンクと画像の参照は、6ページと404ページを合わせて 219件ありました。切れているものは0件です。手で1つずつ押しても数十分あれば終わりますが、数が分かっていると「全部見た」と言い切れます

ここまでで OK:要修正がすべて片づき、AIが「OK」と書いた項目も1つは自分の目で確かめた状態。

手で書くのは、直し方の指示

これは手で書く

検品で見つけた不具合を、自分でコードを直さずに、直し方の指示だけを書きます。 直すのはAIですが、何が仕様とどう食い違っているかを言葉にできるのは、指示書を書いた自分だけです。

食い違いを見つけたときは、全部を出し直させないでください。作り直すと、直っていた別の場所が壊れます。渡すのはこの形です。

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

【仕様】
<指示書や渡した文言の、どこにどう書いてあるか>

【いま出ているもの】
<該当のコード>

【食い違い】
<箇条書きで。「〜のはずが、〜になっている」の形>

3つの枠のうち、一番大事なのは【食い違い】です。 「〜のはずが、〜になっている」という形に押し込むと、「なんとなく変」が言葉になります。言葉にならないものは、そもそも直させられません。

ただし、例外を1つ覚えておいてください。3往復しても直らないときと、直しが1行で済むときは、自分で書いたほうが速いです。 今回の min-width: 0 がそれでした。原因が分かっていて、足す場所も1か所で、書く量が1行。ここでプロンプトを組み立てるほうが時間がかかります。

「AIに任せる」は「AIに全部渡す」ではありません。 渡したほうが速いものを渡し、自分で書いたほうが速いものは書く。その線引きができることが、この6回でいちばん増えた力です。

ここまでで OK:見つけた不具合が全部片づき、それぞれ「指示して直させた」か「1行だから自分で直した」かを言える状態。

公開する

ここからが、この教材で初めてやることです。順番を守ってください。

text
① ローカルで検品を全部通す
② Git にコミットする
③ 公開する
④ 公開したURLで、もう一度 Lighthouse と axe を回す
⑤ GA4 のリアルタイムを見る

③の前に④をやりません。 手元では動いていたのに、公開したら画像が出ない、というのはとてもよく起きます。原因はたいてい相対パスの書き方の違いです。公開したURLで測って初めて、公開されたものの合否が分かります。

Git で履歴を残す

Git は、いつ・何を・なぜ変えたかを、あとから読める形で残す仕組みです。サイトのフォルダの中で、最初に1回だけ準備します。

bash
git init

次に、履歴に入れたくないものを書いた .gitignore というファイルを1枚作ります。中身は3行です。

text
.DS_Store
node_modules/
shots/

.DS_Store はパソコンがフォルダごとに勝手に作る設定ファイル、shots/ は検品で撮ったスクリーンショットの置き場です。どちらもサイトの中身ではないので、履歴には入れません。ここまでできたら、最初のコミット(変更をひとまとまりにして記録すること)です。

bash
git add .
git commit -m "feat: ミナモ製作所のサイトを作る"

以降は、区切りがつくたびに1本打ちます。合格の条件は「5本以上」ですが、数より中身です。

良いコミットメッセージ良くない例
fix: 390px で works.html が横に伸びるのを直すfix
feat: お問い合わせフォームと404ページを足すupdate
fix: 実績カードの alt を写真の説明に直すいろいろ修正

メッセージを書くのは自分です。ここはAIに渡しません。 半年後にこの履歴を読むのは自分で、そのとき知りたいのは「何を変えたか」ではなく「なぜ変えたか」だからです。fix: 390px で横に伸びるのを直す と書いてあれば、次に同じ症状が出たとき、この行から当時の直し方に戻れます。

検品

bash
git log --oneline

合格の見え方意味の分かるコミットが5本以上並ぶこと。update fix だけの行は数えません。行を読んで、何を変えたかが分かるものだけを数えてください。

Cloudflare Pages に置く

Cloudflare Pages は、HTMLとCSSと画像が入ったフォルダを、そのままインターネットに置ける場所です。作ったものはビルド(変換)が要らない素のHTMLなので、置くだけで動きます。

やり方は2通りあります。おすすめはAです。

A:Gitと連携する。 GitHub(Gitの履歴を預ける場所)にリポジトリを作って、いま作った履歴を送ります。そのあと Cloudflare の管理画面に入り、Pages のプロジェクトを新しく作って、「Gitと接続する」を選びます。さっき作ったリポジトリを選び、ビルドコマンドは空のまま出力するフォルダはリポジトリの一番上を指定します。あとは待つだけで、.pages.dev で終わるURLが1つもらえます。以降は、Gitに新しいコミットを送るたびに自動で公開が更新されます

B:コマンドで直接送る。 手元のフォルダを1回きりで送る方法です。プロジェクト名は自分で決めます。

bash
npx wrangler pages deploy . --project-name <自分で決めたプロジェクト名>

Aをすすめるのは、公開されているものと手元のものがずれないからです。Bは手軽ですが、「手元では直したのに、公開されているのは古いまま」が起こります。

アカウントの作り方、無料でどこまでできるか、独自ドメイン(自分で買ったURL)の付け方は、公式の案内に従ってください。 この手の画面と条件は変わります。変わらないのは「ビルド無しの静的なフォルダを、Gitと繋いで置く」という筋道のほうです。

合格の見え方https://<プロジェクト名>.pages.dev/ が開き、ヘッダーのナビから6ページ全部に行けること。そして、存在しないURL(/abc など)を打つと 404.html が出ること。

robots.txt と sitemap.xml を公開URLで見る

公開したら、まずこの2つをブラウザのアドレス欄に直接打って開きます。https://<自分のホスト>/robots.txthttps://<自分のホスト>/sitemap.xml です。

text
User-agent: *
Allow: /

Sitemap: https://minamo-works.example.com/sitemap.xml

robots.txt は検索エンジンへの案内状で、最後の Sitemap: の行が「案内図はここにあります」という意味です。その案内図が sitemap.xml で、見てほしい6ページだけが並んでいます。

text
  <url>
    <loc>https://minamo-works.example.com/index.html</loc>
    <lastmod>2026-09-10</lastmod>
  </url>

lastmod は最後に更新した日付です。未来の日付を書かないでください。実際に触っていない日を書くと、案内図としての信用が落ちます。

ここで大事なのは、この2つのファイルと、各ページの canonical に書いてあるホスト名を、公開先のホスト名に一度に書き換えることです。書き換える場所は次の4か所あります。

書き換える場所何か所
各ページの <link rel="canonical">6
各ページの og:url6
robots.txtSitemap:1
sitemap.xml<loc>6

19か所です。忘れるので、ホスト名は必ず1か所にメモしておいてください。 完成コードでは README.md に「正本はこの1か所」と書いてあります。サンプルは minamo-works.example.com という実在しないホスト名のままにしてあるので、自分のURLに置き換えてから公開します。

GA4 をつなぐ

最後です。GA4 の管理画面でプロパティとデータストリームを作ると、G- で始まる測定IDがもらえます。それを各ページの <head> に入れる1行に書きます。

html
<script src="analytics.js" defer data-ga-id="" data-hosts="minamo-works.example.com"></script>

これがサンプルの状態です。data-ga-id は空、data-hosts は実在しないホスト名になっています。わざとこうしてあります。

理由は1つで、練習用のURLや手元のパソコンから、本物の計測に数字を混ぜないためです。analytics.js の中では、こういう順で判定しています。

見ているもの通す条件
data-ga-idG- で始まる形になっているか
data-hostsいま開いているホスト名が、この中に書いてあるか

両方そろわないと、1件も送りません。 サンプルは測定IDが空なので、そもそも1つ目で止まります。仮に測定IDを入れても、minamo-works.example.com で開いている人はいないので、2つ目でも止まります。二重の鍵がかかっている状態です。

自分のサイトにするときは、この2つを両方書き換えます。

html
<script src="analytics.js" defer data-ga-id="G-XXXXXXXXXX" data-hosts="<自分のpages.devのホスト名>"></script>

data-hosts を空のままにしないでください。 analytics.js は、ホスト名の指定が無いときは .pages.dev で終わるURLを「仮のURL」とみなして黙るようにしてあります。つまり書かないと、公開したのに1件も数えられません。自分のホスト名をここに明示的に書いて、初めて数え始めます。

これは6ページ全部に入れます。1ページだけ入れ忘れると、そのページに来た人だけが数から消えます。

ここまでで OK:公開URLが開き、6ページのナビが全部つながり、robots.txtsitemap.xml がブラウザで見えて、<head> の1行が自分の値になっている状態。

検品する

この回で新しく足す検品は、公開したあとにしかできない検査です。ブラウザ1つでできます。

検品

bash
open https://<自分のホスト>/robots.txt

合格の見え方Sitemap: の行が自分のホスト名になっていること。この1行が古いホストのままだと、案内図の場所が誰にも伝わりません。

残りの4つは、公開したページを開いてから見ます。

①canonical と OGP。 6ページのどれかを開き、ページのソース(右クリックから「ページのソースを表示」)を出して、canonicalog:urlそのページ自身のURLになっているか見ます。全ページがトップのURLを指しているのが、いちばんよくある事故です。完成コードでは、titlemeta descriptioncanonical6ページとも別の値になっています。

②sitemap.xml。 https://<自分のホスト>/sitemap.xml を開いて、6行だけあることを数えます。404が混ざっていたら消します。

③JSON-LD。 トップのソースに Organization(この会社そのものの情報)が、下層5ページに BreadcrumbList(どこから来てどこにいるかの道しるべ)が入っているか見ます。トップに道しるべは要りませんし、下層に会社情報を6回書く必要もありません。

④GA4 が1回だけ飛ぶか。 ここが今回の山です。DevTools(ブラウザに最初から入っている開発者向けの画面)を開き、Network タブを選んで、フィルタの欄に collect? と打ちます。そのままページを再読み込みします。

出た数意味
1件正常。この状態が合格
2件以上タグが二重。<head> の1行が2回入っているか、別の計測タグも入っている
0件data-ga-iddata-hosts が間違っている(手元で開いているなら0件で正しい)

あわせて、GA4 の「リアルタイム」の画面に自分のアクセスが出ることを見ます。ここまで来て初めて「計測できる状態」です。コードを足しただけでは、まだ計測できていません。

累積の検品は、5回ぶん溜まりました。まとめて通します。公開したURLに対して、もう一度回してください。

検品

bash
npx -y html-validate index.html services.html works.html company.html recruit.html contact.html 404.html
npx -y lighthouse https://<自分のホスト>/ --only-categories=seo,best-practices
npx -y @axe-core/cli https://<自分のホスト>/

合格の見え方:1つ目は7ファイルとも 0 errors。2つ目は SEO と Best Practices に赤い印の項目が無いこと。3つ目は 0 violations

重さは DevTools の Network で測ります。指示書に書いた上限は1ページ1.5MBでした。完成コードの実測はこうです。

ページ1ページの転送量
index.html1.09MB
works.html1.07MB
company.html0.83MB

写真が9枚入って1.09MBに収まっているのは、全部WebPにして、1枚目以外に loading="lazy" を付けているからです。05でやったことが、そのまま効いています。最後に、コマンドで測れないものを手と目で見ます。

見るところ合格
ヘッダーのナビ6ページ全部へ行ける。現在地に下線が出ている
全ページのリンク1回ずつ押して、切れが0
存在しないURL404.html が出る
390px幅7ページとも、横に払っても画面が動かない
フォーム空で送ると止まり、埋めて送ると完了メッセージに変わる
Consoleエラーが1件も出ていない

ここまでで OK:公開URLで6つの検品が全部通り、GA4 のリアルタイムに自分が1人だけ出ている状態。

6サイトを終えて

6サイトで、ずっと同じ3つを繰り返してきました。手で書く/AIに書かせる/検品する。 数字にすると、こう動いています。

010203040506
手で書く100%70%50%30%20%10%
AIに書かせる0%30%50%70%80%90%
検品の項目数123456

手が減った分だけ、検品が増えています。 これは偶然そうしたのではなく、この教材の設計そのものです。手を離せるのは、離した先で何が起きたかを確かめられるようになったときだけです。確かめる方法を持たないまま手を離すと、出てきたものを信じるしかなくなります。

01で全部手で書いたのは、あとで疑うためでした。 display: flex を自分で書いたことがあるから、AIの出したCSSを読んで「これは効かないな」と分かります。02で diff を覚えたから、06で6ページのヘッダーのずれを10秒で見つけられました。03で「先に見る場所を決めておく」を覚えたから、06のフォームで3つの不具合を全部拾えました。順番に意味があります。

そして今回、10%まで減った手の中身は、指示書1枚と、コミットメッセージと、直し方の指示でした。コードではありません。これは「もう書けなくていい」という意味ではなく、書ける人だけが書ける指示がある、という意味です。 影を禁止できたのも、材料の無いページを削れたのも、alt が見出しのコピーだと気づけたのも、全部01から05でやったことの上に立っています。

この教材が最後まで一度も言わなかったことがあります。「AIに任せれば速い」とは書きませんでした。 言ってきたのはずっと「分けると直せる」です。どこまでが自分の判断で、どこからがAIの出力で、何をもって合格とするか。この3つが分かれていれば、半年後に壊れても、自分で直せます。

次に進む道は3つあります。①いま作った6サイトのどれかを、自分の知り合いの本物の事業に置き換えて作り直す(文言が本物になるだけで、検品の難易度は跳ね上がります)。②複数ページを1つの型から書き出す仕組みを覚える(06で手作業でやったヘッダーの統一が、道具でできるようになります)。③公開したサイトの数字を1か月見続ける(GA4を入れた意味は、ここから出ます)。どれから始めても構いません。

00で「未来から来ました、AI秘書の琥珀です!」と名乗ったとき、ボクが渡したかったのは、AIの使い方ではなくこの3つに分ける癖でした。渡し終わったので、ここからは、あなたが自分で分けていく番です。それ、2100年では普通ですよ。

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

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