National Central University
Uedu Main Site
Explore Uedu
Student Console
Register as Member/Login
Research Informed Consent Center
Survey Center
Educational Big Data Challenge
Claim or create a course
Try an AI Scenario Task
Support & Messages
Uptime Data

UeduGPTs

--

Jupyters

3

Local AI

--

Uedu Code

--

中央大學 AQI 80 24°C PM2.5 21
AI Reply Desktop Notifications

Show a desktop notification when the AI TA finishes replying

Chat Message Notifications

Notify me when classmates post messages in the forum

Sound notification

Play an alert sound whenever there is a new notification

Unit 13

盒模型

content、padding、border、margin、box-sizing 與外距合併
Interaction 25 minute(s)

Learning Objectives

  • 說出盒模型由內而外的四層:content、padding、border、margin,以及哪幾層會顯示背景
  • 分辨 box-sizing 的 content-box 與 border-box,算出元素實際佔的寬度
  • 說明為什麼常在全站設定 box-sizing: border-box
  • 預測上下相鄰區塊的外距合併結果,並用 margin: 0 auto 讓區塊水平置中
  • 分辨 display 的 block、inline、inline-block,說明 inline 元素為什麼設了 width 沒有作用

網頁上的每個元素都是一個盒子

看一張社團介紹卡片:文字離卡片邊緣留了一點空白、卡片有一圈框線、兩張卡片之間隔開一段距離。 這三種「距離」在 CSS 裡是三個不同的屬性,而且會影響卡片最後有多寬。

瀏覽器排版時,把每一個元素都當成一個矩形的盒子:段落是盒子、標題是盒子、連結也是盒子。 排版的工作就是決定每個盒子多大、放在哪裡。這套規則叫做盒模型(box model)。

很多排版上的疑問都出在盒模型:

常見的狀況 原因(這一課會講)
設了 width: 300px,量起來卻比 300px 寬 width 預設只算內容,padding 與 border 另外加上去
兩個段落各有 20px 的外距,中間卻只隔 20px 上下相鄰的外距會合併
給 <span> 設寬度,完全沒有反應 span 是 inline 元素,width 對它沒有作用

打開瀏覽器的開發者工具(第 1 課),選一個元素,「Computed」分頁就會畫出它的盒模型圖,數字和這一課的工具一樣。

盒子的四層:content、padding、border、margin

一個盒子由內而外分成四層:

層 中文 是什麼 有沒有背景色
content 內容區 文字、圖片所在的區域,width、height 預設就是設定這一層 有
padding 內距 內容與邊框之間的空白 有(和內容同一個背景)
border 邊框 盒子的框線 框線自己的顏色
margin 外距 盒子與旁邊其他盒子之間的距離 沒有,永遠是透明的
.card {
  width: 300px;                   /* content 的寬度 */
  padding: 20px;                  /* 四邊的內距 */
  border: 2px solid #3C6F9A;      /* 粗細、樣式、顏色 */
  margin: 16px 0;                 /* 上下 16px、左右 0 */
}

padding 與 margin 可以寫一到四個值,四個值的順序是上、右、下、左(從上面開始順時針):

寫法 意思
margin: 10px; 四邊都是 10px
margin: 10px 20px; 上下 10px、左右 20px
margin: 10px 20px 30px; 上 10px、左右 20px、下 30px
margin: 10px 20px 30px 40px; 上、右、下、左
margin-top: 10px; 只設定一邊(-right、-bottom、-left 同理)

想讓兩個元素離遠一點用 margin;想讓文字離框線遠一點用 padding。分不清楚時看背景:padding 會被背景色填滿,margin 不會。

width 算到哪裡:content-box 與 border-box

box-sizing 決定 width、height 指的是哪一層:

box-sizing width 指的是 width: 300px; padding: 20px; border: 2px 的實際寬度
content-box(預設值) 只有 content 2 + 20 + 300 + 20 + 2 = 344px
border-box content + padding + border 300px(content 自動縮成 300 − 44 = 256px)

兩種都不含 margin;margin 永遠在 width 之外。

預設的 content-box 讓寬度很難掌握:你想要一張 300px 寬的卡片,每次改 padding 或 border,卡片就跟著變寬。 所以很多網站會在 CSS 的一開始就把所有元素改成 border-box:

*, *::before, *::after {
  box-sizing: border-box;
}

* 選中所有元素;::before、::after 是虛擬元素(第 10 課),也一起改。 這樣寫完之後,width: 300px 就是畫面上看到的 300px,調整 padding 只會擠壓內容,不會撐大盒子。 box-sizing 不會繼承,所以要用 * 每個元素都設定。

上下外距合併與 margin: 0 auto 置中

外距合併(margin collapsing):一般的區塊排列中,上下相鄰的兩個外距不會相加,而是合併成比較大的那一個。

h2 { margin-bottom: 30px; }
p  { margin-top: 20px; }
/* h2 與 p 之間的距離是 30px,不是 50px */

幾個要記的細節:

  • 只有上下方向會合併,左右的外距一定相加。
  • 父元素沒有 padding、border 隔開時,第一個子元素的 margin-top 會「穿出」父元素,和父元素的外距合併。常見的症狀是:子元素設了 margin-top,結果整個父元素往下移。給父元素加一點 padding 或 border 就不會穿出。
  • Flex、Grid 容器裡的項目、浮動(float)與絕對定位的元素,外距都不會合併(第 15、16、17 課)。

水平置中:一個有設定寬度的區塊,左右外距都設成 auto,瀏覽器會把剩下的空間平分到左右兩邊:

.page {
  max-width: 960px;   /* 一定要有寬度,否則區塊本來就佔滿整行,沒有剩下的空間可以分 */
  margin: 0 auto;     /* 上下 0、左右 auto */
}

這是讓整個頁面內容在寬螢幕上置中最常見的寫法。注意它只能水平置中;垂直置中要等 Flexbox(第 17 課)。

盒模型實驗

上半部的盒子由瀏覽器真的排版,右邊的數字是從畫面量回來的。調整滑桿與 box-sizing,看實際寬度怎麼算;下半部調整 A 的 margin-bottom 與 B 的 margin-top,看兩個盒子之間實際隔了多遠。依序完成任務。

互動練習:社團卡片的寬度與間距

兩張社團卡片都設了 width: 300px,量起來卻比 300px 寬,而且貼在左邊。修改 CSS 後按「執行」。預覽寬度可能比卡片窄,可以在預覽裡左右捲動。

小測驗:盒子的寬度與外距

1.

.box { width: 200px; padding: 20px; border: 5px solid; },box-sizing 是預設值。這個盒子在畫面上的寬度(不含 margin)是多少?

2.

同一個盒子改成 box-sizing: border-box,內容區(content)的寬度變成多少?

3.

上下相鄰的兩個段落,上面的 margin-bottom: 30px,下面的 margin-top: 20px。兩段之間實際隔多遠?

4.

對一個 <div> 寫了 margin: 0 auto;,它卻沒有置中。最可能的原因是?

第 1 次作答

display:block、inline 與 inline-block

盒子怎麼排列,由 display 決定。每個元素都有預設值:

display 預設是這個值的元素 排列方式 width、height 上下的 margin
block(區塊) div、p、h1~h6、ul、li、section 自己佔一整行,寬度預設填滿父元素 有作用 有作用
inline(行內) span、a、strong、em、code 跟文字排在同一行,寬度由內容決定 沒有作用 不會推開上下的內容
inline-block button、input(瀏覽器的預設) 跟文字排在同一行,但可以設尺寸 有作用 有作用

inline 元素是「文字的一部分」,它的盒子可能被拆到好幾行,所以 width、height 與上下 margin 都沒有作用; 上下的 padding、border 會畫出來,但不會推開上下行,容易和上一行的文字重疊。左右方向的 padding、margin、border 則正常推開旁邊的文字。

需要「跟文字同一行,又要能設定大小」的時候(標籤、徽章、按鈕樣式的連結),改成 inline-block:

.tag {
  display: inline-block;   /* 仍然和文字排在同一行 */
  width: 80px;             /* 現在有作用了 */
  margin-top: 12px;        /* 上下外距也會推開內容 */
}

反過來,選單的連結預設是 inline,只有文字的範圍可以點。改成 display: block 之後,連結佔滿一整行,整行都可以點,手機上也比較好按。

display: none 會讓元素完全不顯示、也不佔空間,第 16 課會和其他隱藏方式一起比較;flex、grid 是第 17~20 課的主角。

互動練習:標籤與選單的 display

.tag 設了 width: 80px 與 margin-top: 12px,畫面上卻完全沒反應;選單的三個連結擠在同一行,只有文字可以點。修改 CSS 的 display 後按「執行」。

小測驗:padding、margin 與 display

1.

對 <span class="badge"> 設定 width: 100px; height: 40px;,畫面上沒有任何變化。原因是?

2.

padding: 10px 20px; 代表什麼?

3.

卡片有淺藍色背景。想讓文字離卡片邊緣遠一點,而且多出來的空白也是淺藍色,要調整哪一個?

第 1 次作答

重點整理

  • 每個元素都是一個盒子,由內而外是 content、padding、border、margin;padding 有背景,margin 永遠透明。
  • padding、margin 四個值的順序是上、右、下、左;兩個值是上下、左右。
  • 預設的 content-box 中 width 只算內容,padding 與 border 另外加;border-box 的 width 包含 padding 與 border。 常見做法是在全站寫 *, *::before, *::after { box-sizing: border-box; }。
  • 一般區塊排列中,上下相鄰的外距會合併成較大的那一個;Flex、Grid 項目不會合併。
  • 有寬度的區塊用 margin: 0 auto 水平置中。
  • block 自己佔一行;inline 跟文字同一行,width、height 與上下 margin 沒有作用;inline-block 同一行又能設大小。

下一課講背景、邊框與陰影:背景圖片與漸層、圓角、陰影,以及透明度。

這一課完成了!
Next lesson:背景、邊框與陰影
你目前沒有登入,學習進度只存在這個瀏覽器。 Login 後,進度會跟著帳號,換電腦也看得到。