
結論先講
Box Model 是 CSS 所有佈局問題的起點。搞不懂 Box Model 的結果是:
- 設
width: 100%加上padding就爆版 margin為什麼有時候會「合併」不相加width跟min-width/max-width衝突時誰贏- Inline 跟 Block 元素為什麼寬度行為不同
這些不是 bug,是 Box Model 本來就是這樣設計的。這篇把核心模型講清楚,以後看到詭異佈局你會有 mental model 可以推理。
最重要的一條:永遠設 * { box-sizing: border-box; }。下面會講為什麼。
一個 box 有四層
┌─────────────────────────────────┐
│ margin(外邊距,透明) │
│ ┌───────────────────────────┐ │
│ │ border(邊框) │ │
│ │ ┌─────────────────────┐ │ │
│ │ │ padding(內邊距) │ │ │
│ │ │ ┌───────────────┐ │ │ │
│ │ │ │ content │ │ │ │
│ │ │ │ (內容) │ │ │ │
│ │ │ └───────────────┘ │ │ │
│ │ └─────────────────────┘ │ │
│ └───────────────────────────┘ │
└─────────────────────────────────┘
從外到內:
- margin — 跟其他元素的間距
- border — 邊框(有寬度、有顏色)
- padding — 內容跟邊框之間的空白
- content — 文字、圖片、子元素
一個常見誤解:margin 是 box 的一部分嗎?
不是。 margin 不佔 box 的「實際大小」,它只是說「我希望跟鄰居留多少距離」。背景色不會染到 margin 上。
box-sizing:瀏覽器最坑的預設值
這是 CSS 最重要的一個屬性。分兩種模式:
content-box(預設值,坑)
.box {
box-sizing: content-box; /* 預設 */
width: 200px;
padding: 20px;
border: 2px solid black;
}實際寬度:200px + 40px(左右 padding)+ 4px(左右 border)= 244px
你設 width: 200px 結果真的占 244px。每加 padding 都要重算 width。
border-box(你要的)
.box {
box-sizing: border-box;
width: 200px;
padding: 20px;
border: 2px solid black;
}實際寬度:200px(padding 跟 border 被「吸收」進去,content 被擠小)
設 width: 200px 就是 200px。
全域改掉它
每個現代專案都會寫這一條:
*, *::before, *::after {
box-sizing: border-box;
}這不是個人喜好,是業界共識。content-box 是 CSS1 的歷史遺產。
Margin Collapse(最容易被 debug 到懷疑人生的行為)
垂直方向的 margin 會合併不相加:
<h1 style="margin-bottom: 30px;">標題</h1>
<p style="margin-top: 20px;">段落</p>你以為間距是 30 + 20 = 50px? 實際是 30px(取較大值)。
這叫 margin collapse,只發生在垂直方向、block 元素之間。
什麼時候會觸發
- 兩個相鄰 block 元素的 top/bottom margin
- 父元素跟第一個/最後一個子元素(如果父元素沒有 padding、border、非 auto 的 overflow)
- 空的 block 元素的 top 跟 bottom margin
怎麼避免
- 父元素加
padding: 1px(不優雅但有效) - 父元素加
overflow: hidden或auto - 父元素改用 Flexbox 或 Grid(flex/grid item 之間不會 collapse)
實戰:用 Flexbox / Grid 統一處理間距(下一篇會講),不要用 margin 亂噴。
width vs min-width vs max-width
三個寬度屬性同時設時的優先順序:
.box {
width: 500px;
min-width: 300px;
max-width: 800px;
}行為:
- 先套
width: 500px - 如果
width < min-width,用min-width - 如果
width > max-width,用max-width
min/max 永遠勝過 width。
實戰用法:容器寬度限制
.container {
width: 100%;
max-width: 1200px; /* 再大也不超過 1200 */
margin-left: auto;
margin-right: auto; /* 左右 auto = 置中 */
}這是經典的「內容寬度 + 左右空白」排版。
避免 width: 100vw 的坑
100vw 是「視窗寬度」,不扣掉捲軸。如果頁面有垂直捲軸,width: 100vw 會比 width: 100% 寬一點點,產生水平捲軸。
用 width: 100% 或 width: 100dvw(dynamic viewport width)。
Inline vs Block 尺寸行為
不是所有元素都乖乖吃 width:
display | 吃 width? | 吃 height? | 吃 margin? |
|---|---|---|---|
block | ✅ | ✅ | 全吃 |
inline | ❌ | ❌ | 只吃左右 |
inline-block | ✅ | ✅ | 全吃 |
flex / grid item | ✅ | ✅ | 全吃 |
<span> 設 width 沒用
<span style="width: 200px;">文字</span><span> 是 inline,width 被忽略。想吃 width 要:
span { display: inline-block; }
/* 或 */
span { display: block; }實戰 Checklist
- 專案首要:全域
box-sizing: border-box; - 知道 margin 垂直方向會合併
- 用 Flexbox/Grid 管間距,不用一堆 margin 噴
- 知道
max-width勝過width,容器用width: 100%; max-width: Xpx; - 避免
100vw,用100%或100dvw - Inline 元素要
display: inline-block才吃 width
工具:DevTools 看 Box Model
Chrome DevTools 的 Elements 面板右邊有個圖示化的 Box Model:
┌──────── margin ────────┐
│ ┌──── border ────┐ │
│ │ ┌── padding ──┐ │ │
│ │ │ content │ │ │
│ │ └─────────────┘ │ │
│ └────────────────┘ │
└─────────────────────┘
每一層的數字直接改可以即時預覽效果。debug 佈局必備。
相關文章
- CSS 子 Roadmap
- Frontend Roadmap
- 下一篇 → Flexbox 一維佈局(🌱)