STUDENT HTML DOCUMENT

單一章節建立模板

將下列結構建立在 sessions/NN-slug/。資料夾名為歷史相容保留,實際單位是「章節」,不是「一次 180 分鐘課程」。章節時數與課次切片以 course-allocation.json 為準。

必備檔案

NN-slug/
├── index.html
├── teacher-notes.md
├── practice-manifest.json
├── answer-map.html
├── answer-map.md
├── starter/index.html
├── checkpoint-1/index.html
├── checkpoint-2/index.html
└── solution/index.html

practice-manifest.json

{
  "contractVersion": 2,
  "chapterNumber": 1,
  "slug": "web-files-tools",
  "title": "網頁、檔案、瀏覽器與開發工具",
  "durationMinutes": 180,
  "visibleOutcome": "第一個可開啟頁面",
  "objectives": [
    { "id": "OBJ-01", "behavior": "替換頁面標題", "condition": "重新整理後查看瀏覽器分頁", "evidence": "分頁顯示自己的作品名稱", "taskIds": ["TASK-01"] },
    { "id": "OBJ-02", "behavior": "完成自我介紹", "condition": "重新整理後閱讀介紹區", "evidence": "姓名與介紹均為個人內容", "taskIds": ["TASK-02"] },
    { "id": "OBJ-03", "behavior": "建立聯絡入口", "condition": "點擊聯絡連結", "evidence": "瀏覽器辨識 mailto 或開啟 HTTPS 頁面", "taskIds": ["TASK-03"] }
  ],
  "prerequisites": [
    { "id": "PRE-01", "skill": "辨識資料夾、檔案與瀏覽器", "check": "指出目前要修改與查看的檔案", "remediationHref": "../../README.html" },
    { "id": "PRE-02", "skill": "辨識四階段", "check": "指出 TASK-01 與 Checkpoint 1", "remediationHref": "#practice" },
    { "id": "PRE-03", "skill": "描述可見證據", "check": "說出操作後預期看見什麼", "remediationHref": "#learning-goals" }
  ],
  "artifact": {
    "type": "mainline",
    "input": "本機 Starter 專案與個人化內容素材",
    "output": "第一個可開啟頁面",
    "reusedIn": [2]
  },
  "schedule": [
    { "label": "回顧與成果預覽", "type": "teaching", "minutes": 15 },
    { "label": "生活比喻與必要術語", "type": "teaching", "minutes": 20 },
    { "label": "核心觀念與錯誤預測", "type": "teaching", "minutes": 25 },
    { "label": "教師示範與刻意錯誤", "type": "teaching", "minutes": 35 },
    { "label": "休息", "type": "break", "minutes": 10 },
    { "label": "學生跟做與 checkpoint-1", "type": "practice", "minutes": 35 },
    { "label": "獨立任務與 checkpoint-2", "type": "practice", "minutes": 25 },
    { "label": "成果證據與口頭說明", "type": "review", "minutes": 10 },
    { "label": "出口檢核與下堂銜接", "type": "review", "minutes": 5 }
  ],
  "tasks": [
    {
      "id": "TASK-01",
      "doneId": "DONE-01",
      "title": "替換頁面標題",
      "files": ["index.html"],
      "visibleResult": "瀏覽器分頁顯示自己的作品名稱",
      "observe": {
        "prepare": "先記住目前瀏覽器分頁文字。",
        "action": "修改、儲存並重新整理頁面。",
        "expected": "瀏覽器分頁顯示自己的作品名稱"
      },
      "acceptance": { "mode": "dom", "assertions": ["title 文字為學生作品名稱"] },
      "evidence": ["成果截圖包含瀏覽器分頁與頁面標題。"]
    },
    {
      "id": "TASK-02",
      "doneId": "DONE-02",
      "title": "完成自我介紹",
      "files": ["index.html"],
      "visibleResult": "頁面顯示姓名與一段自我介紹",
      "observe": {
        "prepare": "先找到介紹區的範例文字。",
        "action": "替換內容、儲存並重新整理。",
        "expected": "頁面顯示姓名與一段自我介紹"
      },
      "acceptance": { "mode": "dom", "assertions": ["介紹區不再保留範例姓名"] },
      "evidence": ["成果截圖包含完整介紹區。"]
    },
    {
      "id": "TASK-03",
      "doneId": "DONE-03",
      "title": "建立聯絡入口",
      "files": ["index.html"],
      "visibleResult": "聯絡連結可實際點擊",
      "observe": {
        "prepare": "確認連結目前沒有指向個人聯絡方式。",
        "action": "設定 mailto 或 HTTPS 後實際點擊。",
        "expected": "瀏覽器辨識 mailto 或開啟 HTTPS 頁面"
      },
      "acceptance": { "mode": "interaction", "assertions": ["點擊會觸發 mailto 或開啟 HTTPS"] },
      "evidence": ["短錄影呈現點擊前後結果。"]
    }
  ],
  "extensions": []
}

規則:

本章創作挑戰合約

創作挑戰的唯一維護來源是根目錄 creation-path.json,不手動修改 28 份主講義中的產生區塊。每章 challenge 合約為:

{
  "chapterNumber": 1,
  "title": "把範例改成你的第一張個人頁",
  "summary": "用一句短摘要說明學生要做的變化與可見成果。",
  "sessionHref": "sessions/01-web-files-tools/index.html",
  "level": "imitate",
  "gate": false,
  "brief": "一句可驗收、但不指定唯一做法的創作任務。",
  "decisions": ["學生要自己決定的內容一", "學生要自己決定的內容二"],
  "antiCopy": "明確說明不能照搬範例的部分。",
  "evidence": ["可被他人看見或操作的證據", "學生能說明的決策理由"],
  "hints": ["第一層只協助定位", "第二層協助拆解步驟", "第三層提供局部校準方向"],
  "solutionPolicy": "說明可以看什麼,以及必須自己完成什麼。"
}

能力層級固定為 01–06 imitate、07–13 modify、14–20 transfer、21–28 create;第 13、20、28 章 gate 必須為 truesummary 必須是每章唯一的短摘要,並與 CREATION_PATH.html 卡片內的 <small> 精確同步。decisionsevidence 至少兩項,hints 恰好三項,內容不可整段複製其他章。第 26–28 章不得提供學生自選創作挑戰的完整答案;既有 Solution 只核對課堂既定 TASK,不是自選創作的答案。

node tools/build-creation-path.mjs
node tools/check-learning-transfer.mjs

Builder 會在 #practice#evidence 之間產生 <aside id="creation-challenge">,並用 PC_CREATION_CHALLENGE_START / PC_CREATION_CHALLENGE_END marker 安全重跑。區塊顯示 level、brief、decisions、antiCopy、evidence、三個 <details> 提示、solutionPolicy,並連回 ../../CREATION_PATH.html。marker 內不手動加字。

四階段標記

Starter 在要修改的位置保留可見或程式註解標記:


<h1 class="hero__title" id="portfolio-title">請輸入作品名稱</h1>

Checkpoint 可以保留未完成 TASK,已完成項目改成 DONE:


<h1 class="hero__title" id="portfolio-title">小明的作品集</h1>

固定三任務章節的階段集合必須精確一致:Checkpoint-1 恰有 DONE-01;Checkpoint-2 恰有 DONE-01DONE-02;Solution 恰有 DONE-01DONE-02DONE-03。不可提前完成後續任務,也不可在後一階段退回已完成任務。

Solution 的相同位置保留 DONE,HTML 標籤、idclass 不可改:


<h1 class="hero__title" id="portfolio-title">小明的作品集</h1>

如果任務在 CSS 或 JavaScript,標記放在對應檔案。四個階段應保留相同檔名;可改屬性值與程式內容,但不可為了完成答案任意改寫 HTML 結構。

若本章任務本身就是 class rename,可在 manifest 加上明確的一對一例外:

{
  "domContract": {
    "allowedClassRenames": {
      "old-class": "new-class"
    }
  }
}

這個例外只允許 Starter 使用舊 class、Solution 使用新 class;標籤結構、id 與其他 class 仍必須一致,Solution 也不可同時保留新舊名稱。

若教學任務刻意讓某階段保留失效的同頁連結,必須把 stage 與缺失 id 精確列在 manifest:

{
  "domContract": {
    "allowedMissingFragmentsByStage": {
      "starter": ["projects"]
    }
  }
}

這個例外只容許列出的 stage 與 id。該頁必須真的存在 href="#projects"、同時沒有 id="projects";連結被移除或目標補上後,過期豁免也會驗收失敗。除此之外,每個階段頁必須恰好有一個 <main>,所有 href="#id" 都必須找到同頁目標。

answer-map.md 與 answer-map.html

# 練習答案對照

| 任務 | 完成標記 | 修改檔案 | 修改位置 | 可見結果 |
|---|---|---|---|---|
| TASK-01 | DONE-01 | index.html | `#portfolio-title` | 分頁與主標題顯示作品名稱 |
| TASK-02 | DONE-02 | index.html | `.about` | 頁面顯示姓名與自我介紹 |
| TASK-03 | DONE-03 | style.css | `.project-card` | 作品卡片有一致間距與邊框 |

answer map 必須恰好三列任務、五個欄位(任務 ID、完成標記、修改檔案、修改位置、可見結果),並與 practice-manifest.json 的三個 Task 逐列精確一致。每列只能回答一個主要動作。若答案需要一次貼上大量新程式,先把任務拆小,或提供含函式骨架的 starter。

answer-map.md 是教師與維護者編輯的來源;學生只從講義開啟 answer-map.html。修改 Markdown 後執行:

node tools/build-student-docs.mjs

不要在任何學生可見 HTML 寫入指向 .mdhref

teacher-notes.md 最低內容

  1. 本章成果與上一章銜接。
  2. 今日必會、只需辨識、刻意不教。
  3. 等於本章 durationMinutes 的逐段流程,與 manifest 一致,並標出跨課次的分割點。
  4. 生活比喻如何接回實作。
  5. 教師示範步驟與刻意製造的錯誤。
  6. Checkpoint-1、checkpoint-2 的驗收方式。
  7. 常見卡關、排查順序與缺課接回點。
  8. 出口檢核與下一堂銜接。

index.html 唯一 DOM contract

28 章主講義都使用同一份頁面骨架。章節只能補內容,不可自行刪除、改名或調換下列區塊。

Head 與主內容入口

<link rel="icon" href="../../favicon.svg" type="image/svg+xml">
<link rel="stylesheet" href="../../assets/course.css">

<a class="skip-link" href="#lesson-content">跳到主內容</a>
<main id="lesson-content">

</main>
<script src="../../assets/course.js" defer></script>

固定頁首

<header class="site-header">
  <a class="brand" href="../../index.html">
    <img class="brand__mark" src="../../favicon.svg" alt="" aria-hidden="true" width="42" height="42">
    <span>零基礎前端課程</span>
  </a>
  <nav class="header-actions" aria-label="課程導覽">
    <a href="../../index.html#course-list">課程總覽</a>
    <a href="../上一章目錄/index.html" rel="prev">上一章</a>
    <a href="../下一章目錄/index.html" rel="next">下一章</a>
  </nav>
</header>

固定八段順序

固定八個 <section> 之外,builder 會在 practice 後插入創作挑戰 <aside>,不納入八段 section 順序。

<section class="hero" id="hero">...</section>
<section class="principles" id="learning-goals">...</section>
<section class="course-section" id="problem">...</section>
<section class="course-section" id="scope">...</section>
<section class="course-section" id="core-ideas">...</section>
<section class="course-section" id="debugging">...</section>
<section class="course-section" id="practice">...</section>
<section class="course-section" id="evidence">...</section>

八段內容責任依序為:

  1. hero:章次、名稱、可見成果與章節時數。
  2. learning-goals:學生下課時能實際完成的三件事。
  3. problem:本章問題、生活比喻、上一章或上一課次銜接與共同作品位置。
  4. scope:必會、只需辨識、刻意不教與本堂術語。
  5. core-ideas:能解釋畫面責任的核心觀念。
  6. debugging:刻意錯誤、觀察證據與固定排查順序。
  7. practice:Starter → checkpoint-1 → checkpoint-2 → solution 練習路線,以及網頁版 answer-map.html
  8. evidence:成果證據、檢核清單與下一章或下一課次銜接。

結構與內容最低契約:

固定頁尾

<footer class="site-footer">
  <span>第 NN 章 · 本章可見成果</span>
  <a href="../../index.html#course-list">返回課程總覽</a>
</footer>

頁尾成果文字可以依章節調整;兩個直接子元素及順序固定為「成果 span → 返回課程總覽」。頁尾不可放答案對照;#practice 中的網頁版 answer-map.html 連結仍必須保留。