LESSON-05 · 自主延伸

盒模型、尺寸與溢位

把「盒模型、尺寸與溢位」拆成 4 個可獨立完成、可重設、可驗證的自主學習 module。

1. 現在要做什麼

成果:完成一組在窄版不溢位、尺寸限制可解釋的內容卡片。

需要的檔案:files/starter/index.html(整合起點,保留跨 module 的最小缺口。)

完成後:完成一組在窄版不溢位、尺寸限制可解釋的內容卡片。

0 / 8 個操作已記錄

2. 先備自我檢查

逐項展開;答不出來時先走補救連結,不必硬做。

已完成本章基礎練習並能找到 Starter。

自我檢查:我能否指出本章 Starter 入口與唯一 TODO?

不足時補救:回到本章 README,先完成基礎練習與入口導覽。

能開啟本機 HTML 並讀取至少一種瀏覽器證據。

自我檢查:我能否開啟 Elements、Console 或 Network 並找到本頁?

不足時補救:先開 DevTools,重新整理一次,確認目前文件與第一筆 request。

3. 完整學習目標與 Learning Map

每一個目標只對應一個 module;成功狀態必須能指出證據。

能依元素是否要獨佔一行、跟文字同排及接受寬高,選擇 block、inline 或 inline-block。

為什麼重要
display 選錯時,常會誤用 margin 或 position 修補換行與尺寸,讓版面更難維護。
完成條件
在相同文字內容中比較三種 display,並讓 runtime 將同一元素由 block 切為 inline-block。
成功狀態
runtime 的 computed display 由 block 變 inline-block;頁面另可指出 inline 不接受一般 width 的版面差異。
證據位置
runtime before=block、after=inline-block、property=display;另以 Elements 比較三個樣本的換行位置

能用 min-width 與 max-width 為流動寬度設定上下界,而不是把容器固定成單一尺寸。

為什麼重要
只有 width 容易在窄版溢位或在寬螢幕形成過長行長;上下界能保留彈性並限制極端狀態。
完成條件
目標卡片初始沒有最大寬度,執行後加入 bounded-width 並讀取 computed max-width。
成功狀態
runtime 的 max-width 由 none 變 384px;卡片 width:100% 且在窄版不超過父容器。
證據位置
runtime before=none、after=384px、property=max-width;390px 時卡片外框仍位於容器內

能辨識相鄰 block 的垂直 margin 可能合併,並知道建立新的 block formatting context 可阻止父子 margin 穿出。

為什麼重要
若把合併後間距誤當成加總,會不停增加 margin 或插入空元素,造成不同區塊的節奏失控。
完成條件
先觀察父層與第一個子元素的垂直 margin,再以 flow-root 建立新的 formatting context。
成功狀態
runtime 的 display 由 block 變 flow-root;人工量測能指出切換前後父子 margin 是否仍穿出容器。
證據位置
runtime before=block、after=flow-root;人工證據記錄父層與 h2 的 rect.top 差值

能先以 scrollWidth/clientWidth 確認橫向溢位,再針對長字串根因使用 overflow-wrap,而不是隱藏捲軸。

為什麼重要
overflow-x:hidden 只遮住症狀,仍可能裁掉內容、焦點或操作區;修正根因才能保留可讀與可操作性。
完成條件
在有長 URL 的窄卡片中,先記錄溢位,再只切換 overflow-wrap:anywhere。
成功狀態
runtime 的 overflow-wrap 由 normal 變 anywhere;人工重測時 scrollWidth 不再大於 clientWidth。
證據位置
runtime before=normal、after=anywhere、property=overflow-wrap;人工證據為修正後 scrollWidth<=clientWidth

4. 4 個知識模組與 Micro Labs

依序展開;每次只改一項,操作後確認該模組自己的 DOM、progress 與 evidence。

1block、inline、inline-block

完整解釋

白話:block 像整排櫃子;inline 像句子裡的字;inline-block 能跟文字同排,也保留盒子的寬高。

正式說法:display 的 outer/inner display type 決定元素如何參與 flow layout;block-level box 形成區塊,inline box 參與行盒,inline-block 產生 inline-level flow-root box。

何時使用:安排導覽連結、標籤、按鈕或需要可控尺寸又不獨佔一行的元件時。

修改前後:Before:所有元素都靠 width 與 margin 猜排列。After:先選 display mode,再設定尺寸與間距。

常見混淆:HTML 元素的預設 display 不等於永遠不能改;display 也不是 visibility,後者不改變盒子類型。

名詞與最小範例

block、inline、inline-block Block, inline, and inline-block display modes

白話
block 像整排櫃子;inline 像句子裡的字;inline-block 能跟文字同排,也保留盒子的寬高。
正式定義
display 的 outer/inner display type 決定元素如何參與 flow layout;block-level box 形成區塊,inline box 參與行盒,inline-block 產生 inline-level flow-root box。
何時使用
安排導覽連結、標籤、按鈕或需要可控尺寸又不獨佔一行的元件時。
最小範例
.badge { display:inline-block; width:8rem; }
驗收證據
runtime before=block、after=inline-block、property=display;另以 Elements 比較三個樣本的換行位置
常混淆
HTML 元素的預設 display 不等於永遠不能改;display 也不是 visibility,後者不改變盒子類型。

Micro Lab|block、inline、inline-block

情境:服務標籤需要留在同一行又要有固定 padding 與寬度,但目前使用 block 導致每個標籤都換行。

起始狀態:被測標籤是 block;旁邊另有固定 inline 與 inline-block 對照樣本。

  1. 執行實驗切換 display-inline-block class,讀取目標元素切換前後的 computed display。
  2. 執行下方操作,觀察獨立的 DOM 與資料狀態。
  3. 依證據欄位重新驗收。

目前主題:block、inline、inline-block

被測標籤inline 對照inline-block 對照
尚未執行;DOM data-state=starter。

預期:runtime 的 computed display 由 block 變 inline-block;頁面另可指出 inline 不接受一般 width 的版面差異。

證據:runtime before=block、after=inline-block、property=display;另以 Elements 比較三個樣本的換行位置

第一個檢查:在 Computed 搜尋 display,先確認目標初始值為 block。

重設:重新載入 module,讓目標移除 display-inline-block class。

卡住時

  • 症狀:切換後仍顯示 block。
    可能原因:className 沒加到被測元素,或較高權重規則仍指定 display:block。
    先檢查:查看目標 class list 與 Styles 中 display 規則來源。
    修正:讓 .display-inline-block 明確命中同一目標並移除衝突規則。

理解檢查

哪個 display 適合要跟文字同排又需要可靠寬高的標籤?

尚未作答。

查看解釋

inline-block 產生 inline-level box,同時保留可控制的盒子尺寸。

本模組官方來源:MDN|display

2min/max-width

完整解釋

白話:width 是想要的大小,min-width 是不能再小,max-width 是不能再大。

正式說法:min-width 與 max-width 對 used width 建立 lower/upper constraint;當限制衝突時,min-width 的約束優先於 max-width。

何時使用:內容容器、卡片、表單或圖片需要隨可用空間縮放,但不能過窄或過寬時。

修改前後:Before:卡片在大螢幕拉滿整行。After:width 保持流動,max-width 限制可讀寬度。

常見混淆:max-width 不是固定 width;可用空間小於上限時,元素仍可縮小。

名詞與最小範例

min/max-width Minimum and maximum width constraints

白話
width 是想要的大小,min-width 是不能再小,max-width 是不能再大。
正式定義
min-width 與 max-width 對 used width 建立 lower/upper constraint;當限制衝突時,min-width 的約束優先於 max-width。
何時使用
內容容器、卡片、表單或圖片需要隨可用空間縮放,但不能過窄或過寬時。
最小範例
.card { width:100%; min-width:0; max-width:24rem; }
驗收證據
runtime before=none、after=384px、property=max-width;390px 時卡片外框仍位於容器內
常混淆
max-width 不是固定 width;可用空間小於上限時,元素仍可縮小。

Micro Lab|min/max-width

情境:服務卡在桌機橫跨整頁造成行長過長,但手機又需要使用全部可用寬度。

起始狀態:卡片 width:100%,未設定 max-width。

  1. 執行實驗替卡片切換 bounded-width class,讀取 max-width 的 before/after。
  2. 執行下方操作,觀察獨立的 DOM 與資料狀態。
  3. 依證據欄位重新驗收。

目前主題:min/max-width

流動服務卡
尚未執行;DOM data-state=starter。

預期:runtime 的 max-width 由 none 變 384px;卡片 width:100% 且在窄版不超過父容器。

證據:runtime before=none、after=384px、property=max-width;390px 時卡片外框仍位於容器內

第一個檢查:先在 Computed 確認 max-width 為 none,不先改父層寬度。

重設:重新載入 module,移除 bounded-width class。

卡住時

  • 症狀:390px 預覽仍出現水平捲軸。
    可能原因:卡片另有固定 width、min-width 過大,或 padding 未納入 box sizing。
    先檢查:比較卡片 computed width/max-width/min-width 與父層 clientWidth。
    修正:移除固定寬度,採 width:100%、min-width:0,並使用 border-box。

理解檢查

為何 `width:100%; max-width:24rem` 不等於固定 24rem?

尚未作答。

查看解釋

width 提供流動尺寸,max-width 只限制上界。

本模組官方來源:MDN|max-width

3margin collapse

完整解釋

白話:兩個垂直外距有時會疊成一個,不是永遠相加;flow-root 像替容器建立自己的排版邊界。

正式說法:在 block formatting context 中,特定相鄰 block-level boxes 的垂直 margins 會 collapse;建立新的 BFC 可阻止父子 margin collapse。

何時使用:區塊上下距離與兩個 margin 數值加總不同,或第一個子元素 margin 看似跑到父層外時。

修改前後:Before:看到 24px 與 32px 就宣稱間距是 56px。After:以 rect 差值辨認合併,必要時建立 BFC。

常見混淆:Flex/Grid item 的 margins 不會以相同規則 collapse;gap 也不是 margin collapse。

名詞與最小範例

margin collapse Margin collapsing

白話
兩個垂直外距有時會疊成一個,不是永遠相加;flow-root 像替容器建立自己的排版邊界。
正式定義
在 block formatting context 中,特定相鄰 block-level boxes 的垂直 margins 會 collapse;建立新的 BFC 可阻止父子 margin collapse。
何時使用
區塊上下距離與兩個 margin 數值加總不同,或第一個子元素 margin 看似跑到父層外時。
最小範例
.section { display:flow-root; } .section > h2 { margin-top:2rem; }
驗收證據
runtime before=block、after=flow-root;人工證據記錄父層與 h2 的 rect.top 差值
常混淆
Flex/Grid item 的 margins 不會以相同規則 collapse;gap 也不是 margin collapse。

Micro Lab|margin collapse

情境:區塊第一個 h2 的 margin-top 看似把整個 section 推開,而不是只在 section 內留白。

起始狀態:section 是一般 block,第一個 h2 有 32px margin-top,父層沒有 border/padding。

  1. 執行實驗替父層切換 establish-bfc,確認 computed display 由 block 變 flow-root,再用 rect 量測父子上緣。
  2. 執行下方操作,觀察獨立的 DOM 與資料狀態。
  3. 依證據欄位重新驗收。

目前主題:margin collapse

服務標題

說明內容

尚未執行;DOM data-state=starter。

預期:runtime 的 display 由 block 變 flow-root;人工量測能指出切換前後父子 margin 是否仍穿出容器。

證據:runtime before=block、after=flow-root;人工證據記錄父層與 h2 的 rect.top 差值

第一個檢查:先讀 section 與 h2 的 getBoundingClientRect().top,不先加 padding。

重設:重新載入 module,移除 establish-bfc class。

卡住時

  • 症狀:切換 flow-root 後畫面沒有任何差異。
    可能原因:父層已有 border/padding、子元素不是第一個 in-flow child,或原本就在 Flex/Grid context。
    先檢查:檢查父層 border/padding/display 與子元素 DOM 位置。
    修正:恢復最小 fixture:一般 block、無 border/padding、第一個 h2 有 margin-top。

理解檢查

哪一種方法可建立新的 block formatting context 來阻止父子 margin collapse?

尚未作答。

查看解釋

flow-root 會建立新的 BFC,改變 margin collapse 邊界。

本模組官方來源:MDN|Mastering margin collapsing

4overflow 症狀與根因

完整解釋

白話:先量內容是不是超出去,再找是哪個盒子或哪段不能換行的文字把版面撐開。

正式說法:Overflow 發生於內容超出 box 的 padding box;overflow-wrap:anywhere 允許原本不可斷的字串在必要處換行,但不應取代尺寸與 min-content 根因分析。

何時使用:390px 出現水平捲軸、長 URL/訂單編號撐開卡片,或 focus outline 被裁切時。

修改前後:Before:直接在 body 加 overflow-x:hidden。After:找出第一個 scrollWidth>clientWidth 的元素並修正其長內容策略。

常見混淆:overflow-wrap 修長字串,不會修正寫死 900px width;不同根因需要不同修正。

名詞與最小範例

overflow 症狀與根因 Overflow symptoms and root causes

白話
先量內容是不是超出去,再找是哪個盒子或哪段不能換行的文字把版面撐開。
正式定義
Overflow 發生於內容超出 box 的 padding box;overflow-wrap:anywhere 允許原本不可斷的字串在必要處換行,但不應取代尺寸與 min-content 根因分析。
何時使用
390px 出現水平捲軸、長 URL/訂單編號撐開卡片,或 focus outline 被裁切時。
最小範例
.long-url { overflow-wrap:anywhere; }
驗收證據
runtime before=normal、after=anywhere、property=overflow-wrap;人工證據為修正後 scrollWidth<=clientWidth
常混淆
overflow-wrap 修長字串,不會修正寫死 900px width;不同根因需要不同修正。

Micro Lab|overflow 症狀與根因

情境:手機版只有一張含長 URL 的服務卡造成整頁水平捲動。

起始狀態:卡片寬度受容器限制,但長 URL 使用 overflow-wrap:normal。

  1. 執行實驗替長 URL 切換 wrap-anywhere,讀取 computed overflow-wrap,再重新比較卡片 scrollWidth/clientWidth。
  2. 執行下方操作,觀察獨立的 DOM 與資料狀態。
  3. 依證據欄位重新驗收。

目前主題:overflow 症狀與根因

https://example.com/services/this-is-a-very-long-unbroken-service-reference-number-2026

尚未執行;DOM data-state=starter。

預期:runtime 的 overflow-wrap 由 normal 變 anywhere;人工重測時 scrollWidth 不再大於 clientWidth。

證據:runtime before=normal、after=anywhere、property=overflow-wrap;人工證據為修正後 scrollWidth<=clientWidth

第一個檢查:在 Console 比較長 URL 元素與文件的 scrollWidth/clientWidth,確認第一個超寬元素。

重設:重新載入 module,移除 wrap-anywhere class。

卡住時

  • 症狀:套用 anywhere 後整頁仍水平溢位。
    可能原因:真正根因是固定 width、transform 位移或其他元素,不是這段長字串。
    先檢查:逐層比較 document 與子元素的 scrollWidth/clientWidth,找第一個超寬盒。
    修正:保留長字串修正,再移除真正超寬元素的固定尺寸或位移。

理解檢查

為什麼不應先用 overflow-x:hidden?

尚未作答。

查看解釋

隱藏 overflow 不會消除造成超寬的盒子或不可斷內容。

本模組官方來源:MDN|overflow

5. 盒模型、尺寸與溢位|整合 Lab

情境:在同一份章節作品中整合 4 個 module,排除單項通過但組合失敗的問題。

交付:完成一組在窄版不溢位、尺寸限制可解釋的內容卡片。

尚未執行整合步驟。
  1. 1觀察整合 Starter 並找出第一個未通過 module。

    檔案:files/starter/index.html 定位:#observe

    操作:逐項讀取 outcomes,執行一次現況操作。

    // OBSERVE:不修改程式,先記錄第一個失敗 moduleId。

    預期:能指出第一個未通過 module。

    證據:第一個 moduleId 與缺少的 evidence。

    原因:先觀察可避免未重現就直接改答案。

    卡住先查:確認開啟的是 files/starter/index.html。

  2. 2依 module 順序修改,一次只加入一個責任。

    檔案:files/starter/index.html 定位:#modify

    操作:執行實驗切換 display-inline-block class,讀取目標元素切換前後的 computed display。 → 執行實驗替卡片切換 bounded-width class,讀取 max-width 的 before/after。 → 執行實驗替父層切換 establish-bfc,確認 computed display 由 block 變 flow-root,再用 rect 量測父子上緣。 → 執行實驗替長 URL 切換 wrap-anywhere,讀取 computed overflow-wrap,再重新比較卡片 scrollWidth/clientWidth。

    // 05-01-block-inline-inline-block: 執行實驗切換 display-inline-block class,讀取目標元素切換前後的 computed display。
    // 05-02-min-max-width: 執行實驗替卡片切換 bounded-width class,讀取 max-width 的 before/after。
    // 05-03-margin-collapse: 執行實驗替父層切換 establish-bfc,確認 computed display 由 block 變 flow-root,再用 rect 量測父子上緣。
    // 05-04-overflow: 執行實驗替長 URL 切換 wrap-anywhere,讀取 computed overflow-wrap,再重新比較卡片 scrollWidth/clientWidth。

    預期:完成一組在窄版不溢位、尺寸限制可解釋的內容卡片。

    證據:runtime before=block、after=inline-block、property=display;另以 Elements 比較三個樣本的換行位置;runtime before=none、after=384px、property=max-width;390px 時卡片外框仍位於容器內;runtime before=block、after=flow-root;人工證據記錄父層與 h2 的 rect.top 差值;runtime before=normal、after=anywhere、property=overflow-wrap;人工證據為修正後 scrollWidth<=clientWidth

    原因:逐項整合能把回歸定位到明確 module。

    卡住先查:回到第一個未通過的 module,只修該處。

  3. 3驗證所有 module 在整合後仍成立。

    檔案:files/solution/index.html 定位:#verify

    操作:重新整理並依 outcomes 順序重跑所有證據。

    // VERIFY:逐項記錄 pass/fail,不以看到畫面代替 evidence。

    預期:4/4 module 通過。

    證據:每個 moduleId 都有實際結果與重設後重現紀錄。

    原因:單項通過不代表整合後沒有 selector、id 或狀態衝突。

    卡住先查:若失敗,回到第一個失敗 module,不同時修多項。

  4. 4把本章責任轉用到不同內容情境。

    檔案:files/starter/index.html 定位:#challenge

    操作:替另一個商家情境重做,仍達成:完成一組在窄版不溢位、尺寸限制可解釋的內容卡片。

    // CHALLENGE:只替換內容與資料,不新增框架或跳過 self-check。

    預期:完成一組在窄版不溢位、尺寸限制可解釋的內容卡片。

    證據:轉用後的作品與全數 module self-check。

    原因:能轉用才代表理解責任,而非只記住原範例。

    卡住先查:先確認共同基底與 module id 未被改壞。

重設方法:重新載入 files/starter/index.html;若 localStorage 不可用,使用頁面內記憶狀態並提供重設按鈕。

6. 自學挑戰與三層提示

挑戰:將同一組責任轉用到另一個商家情境,仍達成:完成一組在窄版不溢位、尺寸限制可解釋的內容卡片。

限制:不新增框架。;保留 module id 與驗收證據。

提交證據:提交可直接開啟的作品與逐項 self-check。

提示 1|方向提示

拆小:在「盒模型、尺寸與溢位」先完成第一個尚未通過的 module:block、inline、inline-block,不同時修改其他責任。

提示 2|關鍵片段

串接:依 05-01-block-inline-inline-block → 05-02-min-max-width → 05-03-margin-collapse → 05-04-overflow 核對各自輸入與證據。

提示 3|完整解答與原因

完整解答與原因:依序執行 執行實驗切換 display-inline-block class,讀取目標元素切換前後的 computed display。 → 執行實驗替卡片切換 bounded-width class,讀取 max-width 的 before/after。 → 執行實驗替父層切換 establish-bfc,確認 computed display 由 block 變 flow-root,再用 rect 量測父子上緣。 → 執行實驗替長 URL 切換 wrap-anywhere,讀取 computed overflow-wrap,再重新比較卡片 scrollWidth/clientWidth。;這個順序能把每個結果對回單一 module,避免整合後無法定位。

完整解答預設收合;先留下自己的嘗試,再開第三層。

7. 症狀式除錯指南

8. 理解測驗、驗收證據與下一步

哪個狀態代表 05-01-block-inline-inline-block 完成?

尚未作答。

查看解釋

display 選錯時,常會誤用 margin 或 position 修補換行與尺寸,讓版面更難維護。

哪個狀態代表 05-02-min-max-width 完成?

尚未作答。

查看解釋

只有 width 容易在窄版溢位或在寬螢幕形成過長行長;上下界能保留彈性並限制極端狀態。

哪個狀態代表 05-03-margin-collapse 完成?

尚未作答。

查看解釋

若把合併後間距誤當成加總,會不停增加 margin 或插入空元素,造成不同區塊的節奏失控。

哪個狀態代表 05-04-overflow 完成?

尚未作答。

查看解釋

overflow-x:hidden 只遮住症狀,仍可能裁掉內容、焦點或操作區;修正根因才能保留可讀與可操作性。

驗收清單

官方來源

回到課程地圖選擇下一章