盒模型

CSS 中的每個元素都帶有一個框(盒子),理解這些框對於使用 CSS 建立更復雜的佈局或對齊元素至關重要。在本課程中,我們將深入探討 CSS 盒模型。您將瞭解它的工作原理以及與之相關的術語。

預備知識 HTML 基礎(學習 基本 HTML 語法
學習成果
  • 塊級和行內元素
  • 構成元素的各種框以及如何設定它們的樣式——內容、外邊距、邊框、內邊距。
  • 替代盒模型(透過 box-sizing: border-box 訪問)以及它與常規盒模型的區別。
  • 外邊距摺疊。
  • 基本的顯示值及其對盒行為的影響——blockinlineinline-blocknone

塊級和行內框

在 CSS 中,我們有幾種型別的框,通常分為塊級框行內框。型別指的是框在頁面流以及與頁面上其他框的關係方面的行為方式。框具有內部顯示型別外部顯示型別

通常,您可以使用 display 屬性為顯示型別設定各種值。

如果一個框的顯示值為 block,那麼

  • 該框將換行。
  • widthheight 屬性受尊重。
  • 內邊距、外邊距和邊框將導致其他元素被推離該框。
  • 如果未指定 width,則該框將在行內方向上延伸以填充其容器中可用的空間。在大多數情況下,該框將變得與其容器一樣寬,填充 100% 的可用空間。

一些 HTML 元素,例如 <h1><p>,預設使用 block 作為其外部顯示型別。

如果一個框的顯示型別為 inline,那麼

  • 該框不會換行。
  • widthheight 以及上下外邊距將不起作用。
  • 上下內邊距和邊框將改變框的大小,而不影響周圍內容的位置,這可能導致重疊。
  • 左右內邊距、外邊距和邊框將影響周圍行內內容的位置。

一些 HTML 元素,例如 <a><span><em><strong>,預設使用 inline 作為其外部顯示型別。

塊級和行內佈局是網頁上元素的預設行為方式。預設情況下,在沒有任何其他指令的情況下,框內的元素也會以正常流方式佈局,並表現為塊級或行內框。

內部和外部顯示型別

blockinline 顯示值被稱為外部顯示型別——它們影響框相對於周圍其他框的佈局方式。框還具有內部顯示型別,它決定了該框內部元素的佈局方式。

您可以透過設定內部顯示值來改變內部顯示型別,例如 display: flex;。該元素仍將使用外部顯示型別 block,但這會將內部顯示型別更改為 flex。該框的任何直接子元素都將成為彈性項,並根據 彈性盒(Flexbox)規範進行行為。

當您更詳細地學習 CSS 佈局時,您會遇到 flex 以及您的框可以擁有的各種其他內部值,例如 grid

暫時不必太擔心內部和外部的術語;這是內部發生的事情,我們在這裡提到它以防您在其他地方遇到它。通常,您只需處理單個 display 值,而無需過多考慮它。

不同顯示型別的示例

下面的示例有三個不同的 HTML 元素,它們都具有 block 的外部顯示型別。

  • 一個在 CSS 中添加了邊框的段落。瀏覽器將其渲染為塊級框。該段落從新行開始,並水平延伸以填充整個可用寬度。

  • 一個列表,使用 display: flex 佈局。這為容器的子元素建立了彈性佈局,子元素是預設按行佈局的彈性項。列表本身是一個塊級框,並且——像段落一樣——擴充套件到整個容器寬度並換行。

  • 一個塊級段落,其中包含兩個 <span> 元素。這些元素通常是 inline,但是,其中一個元素具有 block 類,並設定為 display: block。結果是,那個單詞從新行開始,並橫跨其父元素的整個寬度。

html
<p>I am a paragraph. A short one.</p>
<ul>
  <li>Item One</li>
  <li>Item Two</li>
  <li>Item Three</li>
</ul>
<p>
  I am another paragraph. Some of the <span class="block">words</span> have been
  wrapped in a <span>span element</span>.
</p>
css
body {
  font-family: sans-serif;
}
p,
ul {
  border: 2px solid rebeccapurple;
  padding: 0.2em;
}

.block,
li {
  border: 2px solid blue;
  padding: 0.2em;
}

ul {
  display: flex;
  list-style: none;
}

.block {
  display: block;
}

在下一個示例中,我們可以看到 inline 元素的行為方式。

  • 第一個段落中的 <span> 元素預設是行內的,因此不會強制換行。

  • 設定為 display: inline-flex<ul> 元素建立一個包含一些彈性項的行內框。

  • 這兩個段落都設定為 display: inline。行內彈性容器和段落都一起在一行上執行,而不是換行(如果它們顯示為塊級元素,它們就會換行)。

要在顯示模式之間切換,您可以將 display: inline 更改為 display: block 或將 display: inline-flex 更改為 display: flex

html
<p>
  I am a paragraph. Some of the
  <span>words</span> have been wrapped in a <span>span element</span>.
</p>
<ul>
  <li>Item One</li>
  <li>Item Two</li>
  <li>Item Three</li>
</ul>
<p class="inline">I am a paragraph. A short one.</p>
<p class="inline">I am another paragraph. Also a short one.</p>
css
body {
  font-family: sans-serif;
}
p,
ul {
  border: 2px solid rebeccapurple;
}

span,
li {
  border: 2px solid blue;
}

ul {
  display: inline-flex;
  list-style: none;
  padding: 0;
}

.inline {
  display: inline;
}

目前需要記住的關鍵是:更改 display 屬性的值可以改變框的外部顯示型別是塊級還是行內。這會改變它在佈局中與其他元素一起顯示的方式。

什麼是 CSS 盒模型?

CSS 盒模型作為一個整體適用於塊級框,並定義了框的不同部分——外邊距、邊框、內邊距和內容——如何協同工作以建立您可以在頁面上看到的框。行內框只使用盒模型中定義的部分行為。

為了增加複雜性,存在標準盒模型和替代盒模型。預設情況下,瀏覽器使用標準盒模型。

框的組成部分

在 CSS 中構成一個塊級框,我們有

  • 內容框:顯示內容的區域;使用 widthheight 等屬性調整其大小。
  • 內邊距框:內邊距圍繞內容作為空白;使用 padding 和相關屬性調整其大小。
  • 邊框框:邊框框包裹內容和任何內邊距;使用 border 和相關屬性調整其大小。
  • 外邊距框:外邊距是最外層,包裹內容、內邊距和邊框作為此框與其他元素之間的空白;使用 margin 和相關屬性調整其大小。

下圖顯示了這些層

Diagram of the box model

標準 CSS 盒模型

在標準盒模型中,如果您在框上設定 widthheight 屬性值,這些值定義了內容框widthheight。然後將任何內邊距和邊框新增到這些尺寸中,以獲得框所佔用的總大小(請參見下圖)。

如果我們假設一個框具有以下 CSS

css
.box {
  width: 350px;
  height: 150px;
  margin: 10px;
  padding: 25px;
  border: 5px solid black;
}

該框實際佔用的空間將是 410px 寬(350 + 25 + 25 + 5 + 5)和 210px 高(150 + 25 + 25 + 5 + 5)。

Showing the size of the box when the standard box model is being used.

注意: 外邊距不計入框的實際大小——當然,它會影響框在頁面上佔用的總空間,但僅限於框外部的空間。框的區域止於邊框——它不會延伸到外邊距中。

替代 CSS 盒模型

在替代盒模型中,任何寬度都是頁面上可見框的寬度。內容區域寬度是該寬度減去內邊距和邊框的寬度(參見下圖)。這很方便,因為無需將邊框和內邊距加起來即可獲得框的實際大小。

要為元素開啟替代模型,請在其上設定 box-sizing: border-box

css
.box {
  box-sizing: border-box;
}

如果我們假設該框具有與上面相同的 CSS

css
.box {
  width: 350px;
  height: 150px;
  margin: 10px;
  padding: 25px;
  border: 5px solid black;
}

該框實際佔用的空間現在將是行內方向 350px,塊級方向 150px

Showing the size of the box when the alternate box model is being used.

要為所有元素使用替代盒模型(這是開發人員的常見選擇),請在 <html> 元素上設定 box-sizing 屬性,並將所有其他元素設定為繼承該值

css
html {
  box-sizing: border-box;
}

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

要理解其基本思想,您可以閱讀 CSS Tricks 關於 box-sizing 的文章

玩轉盒模型

在下面的示例中,您可以看到兩個框。兩者都具有 .box 類,這使得它們具有相同的 widthheightmarginborderpadding。唯一的區別是第二個框已設定為使用替代盒模型。您能否更改第二個框的大小(透過向 .alternate 類新增 CSS)以使其在寬度和高度上與第一個框匹配?

html
<div class="box">I use the standard box model.</div>
<div class="box alternate">I use the alternate box model.</div>
css
.box {
  border: 5px solid rebeccapurple;
  background-color: lightgray;
  padding: 40px;
  margin: 40px;
  width: 300px;
  height: 150px;
}

.alternate {
  box-sizing: border-box;
}

注意: 您可以在我們的 css-examples 倉庫中找到此任務的解決方案:css-examples 倉庫

使用瀏覽器開發工具檢視盒模型

您的瀏覽器開發工具可以使理解盒模型變得容易得多——它們可以向您顯示元素的大小以及其外邊距、內邊距和邊框。以這種方式檢查元素是瞭解您的框是否確實是您認為的大小的好方法!

Inspecting the box model of an element using Firefox DevTools

外邊距、內邊距和邊框

您已經在上面的示例中看到了 marginpaddingborder 屬性的作用。該示例中使用的屬性是簡寫,允許我們一次設定框的所有四個側面。這些簡寫也有等效的長手屬性,允許單獨控制框的不同側面。

讓我們更詳細地探討這些屬性。

外邊距

外邊距是框周圍的不可見空間。它將其他元素推離框。外邊距可以具有正值或負值。在框的一側設定負外邊距可能會導致它與頁面上的其他內容重疊。無論您使用的是標準盒模型還是替代盒模型,外邊距始終在計算可見框的大小之後新增。

我們可以使用 margin 屬性一次控制元素的所有外邊距,或者使用等效的長手屬性單獨控制每個側面

玩轉外邊距

編輯下面的示例。嘗試更改外邊距值,看看由於外邊距在此元素和包含元素之間建立或移除空間(如果是負外邊距)而導致框如何被推來推去。

html
<div class="container">
  <div class="box">Change my margin.</div>
</div>
css
.container {
  border: 5px solid blue;
  margin: 40px;
}

.box {
  border: 5px solid rebeccapurple;
  background-color: lightgray;
  padding: 10px;
  height: 100px;
  /* try changing the margin properties: */
  margin-top: -40px;
  margin-right: 30px;
  margin-bottom: 40px;
  margin-left: 4em;
}

外邊距摺疊

根據兩個外邊距接觸的元素是正外邊距還是負外邊距,結果將有所不同

  • 兩個正外邊距將合併成一個外邊距。其大小將等於最大的單個外邊距。
  • 兩個負外邊距將摺疊,並使用最小的(離零最遠)值。
  • 如果一個外邊距是負數,其值將從總數中減去

在下面的示例中,我們有兩個段落。頂部段落的 margin-bottom 為 50 畫素,另一個段落的 margin-top 為 30 畫素。外邊距已摺疊,因此框之間的實際外邊距為 50 畫素,而不是兩個外邊距的總和。

您可以透過將第二個段落的 margin-top 設定為 0 來測試這一點。兩個段落之間可見的外邊距不會改變——它保留了第一個段落 margin-bottom 中設定的 50 畫素。如果您將其設定為 -10px,您將看到總外邊距變為 40px——它從 50px 中減去。

html
<div class="container">
  <p class="one">I am paragraph one.</p>
  <p class="two">I am paragraph two.</p>
</div>
css
.container {
  border: 5px solid blue;
  margin: 40px;
}

p {
  border: 5px solid rebeccapurple;
  background-color: lightgray;
  padding: 10px;
}
.one {
  margin-bottom: 50px;
}

.two {
  margin-top: 30px;
}

許多規則規定了外邊距何時摺疊以及何時不折疊。有關更多資訊,請參閱關於掌握外邊距摺疊的詳細頁面。要記住的主要事情是,如果您正在使用外邊距建立空間但沒有得到預期的空間,那麼外邊距摺疊是會發生的事情。

邊框

邊框繪製在框的外邊距和內邊距之間。如果您使用的是標準盒模型,則邊框的大小會新增到內容框的 widthheight 中。如果您使用的是替代盒模型,則邊框越大,內容框就越小,因為邊框會佔用元素框可用 widthheight 的一部分。

為了設定邊框樣式,有大量的屬性——有四個邊框,每個邊框都有我們可能想要操作的樣式、寬度和顏色。

您可以使用 border 屬性一次設定所有四個邊框的寬度、樣式或顏色。

要單獨設定每個側面的屬性,請使用

要設定所有側面的寬度、樣式或顏色,請使用

要設定單個側面的寬度、樣式或顏色,請使用更細粒度的長手屬性之一

玩轉邊框

在下面的示例中,我們使用了各種簡寫和長手屬性來建立邊框。編輯不同的屬性以檢查您是否理解它們的工作原理。MDN 邊框屬性頁面提供了有關不同可用邊框樣式的資訊。

html
<div class="container">
  <div class="box">Change my borders.</div>
</div>
css
body {
  font-family: sans-serif;
}
.container {
  margin: 40px;
  padding: 20px;
  border-top: 5px dotted green;
  border-right: 1px solid black;
  border-bottom: 20px double rgb(23 45 145);
}

.box {
  padding: 20px;
  background-color: lightgray;
  border: 1px solid #333333;
  border-top-style: dotted;
  border-right-width: 20px;
  border-bottom-color: hotpink;
}

內邊距

內邊距位於邊框和內容區域之間,用於將內容推離邊框。與外邊距不同,您不能有負內邊距。應用於元素的任何背景都將顯示在內邊距後面。

padding 屬性控制元素所有側面的內邊距。要單獨控制每個側面,請使用這些長手屬性

玩轉內邊距

在下面的示例中,編輯類 .box 的內邊距值,看看這如何改變文字相對於框的起始位置。您還可以更改類 .container 的內邊距,以在容器和框之間建立空間。您可以更改任何元素的內邊距,以在其邊框和元素內部的內容之間建立空間。

html
<div class="container">
  <div class="box">Change my padding.</div>
</div>
css
body {
  font-family: sans-serif;
}
.box {
  border: 5px solid rebeccapurple;
  background-color: lightgray;
  padding-top: 0;
  padding-right: 30px;
  padding-bottom: 40px;
  padding-left: 4em;
}

.container {
  border: 5px solid blue;
  margin: 40px;
  padding: 20px;
}

盒模型和行內框

以上所有內容完全適用於塊級框。其中一些屬性也可以應用於行內框,例如由 <span> 元素建立的行內框。

在下面的示例中,我們有一個段落中的 <span>。我們已對其應用 widthheightmarginborderpadding。您可以看到寬度、高度以及上下外邊距不影響 <span>。上下內邊距和邊框會改變行內框的大小,但不會影響周圍內容的位置。相反,上下內邊距和邊框會重疊段落中的其他單詞。只有左右內邊距、外邊距和邊框會影響 <span> 周圍文字的位置。

html
<p>
  I am a paragraph and this is a <span>span</span> inside that paragraph. A span
  is an inline element and so does not respect width and height.
</p>
css
body {
  font-family: sans-serif;
}
p {
  border: 2px solid rebeccapurple;
  width: 200px;
}
span {
  margin: 20px 30px;
  padding: 10px 20px;
  width: 80px;
  height: 150px;
  background-color: lightblue;
  border: solid blue;
  border-width: 7px 1px;
}

使用 display: inline-block

display: inline-blockdisplay 的一個特殊值,它提供了 inlineblock 之間的中間地帶。如果您不希望某個項換行,但又希望它遵守 widthheight 並避免上面看到的重疊,請使用它。

具有 display: inline-block 的元素會執行我們已經知道的塊級事物的一個子集

  • widthheight 屬性受尊重。
  • paddingmarginborder 將導致其他元素被推離該框。

但是,它不會換行,並且只有在您明確新增 widthheight 屬性時才會變得大於其內容。

玩轉 inline-block

在下一個示例中,我們已將 display: inline-block 新增到我們的 <span> 元素。嘗試將其更改為 display: block 或完全刪除該行以檢視顯示模型的差異

html
<p>
  I am a paragraph and this is a <span>span</span> inside that paragraph. A span
  is an inline element and so does not respect width and height.
</p>
css
body {
  font-family: sans-serif;
}
p {
  border: 2px solid rebeccapurple;
  width: 300px;
}

span {
  margin: 20px;
  padding: 20px;
  width: 80px;
  height: 50px;
  background-color: lightblue;
  border: 2px solid blue;
  display: inline-block;
}

這在您希望透過新增 padding 為連結提供更大的點選區域時非常有用。<a> 是一種行內元素,就像 <span> 一樣;您可以使用 display: inline-block 允許在其上設定內邊距,使使用者更容易點選連結。

您在導航欄中經常看到這種情況。下面的導航使用彈性盒(flexbox)以行形式顯示,我們已向 <a> 元素添加了內邊距,因為我們希望在 <a> 懸停時能夠更改 background-color。內邊距似乎與 <ul> 元素上的邊框重疊。這是因為 <a> 是一個行內元素。

在帶有 .links-list a 選擇器的規則中新增 display: inline-block;,您將看到它如何透過使其他元素尊重內邊距來解決此問題

html
<nav>
  <ul class="links-list">
    <li><a href="">Link one</a></li>
    <li><a href="">Link two</a></li>
    <li><a href="">Link three</a></li>
  </ul>
</nav>
css
ul {
  font-family: sans-serif;
  display: flex;
  list-style: none;
  border: 1px solid black;
}

li {
  margin: 5px;
}

.links-list a {
  background-color: rgb(179 57 81);
  color: white;
  text-decoration: none;
  padding: 1em 2em;
}

.links-list a:hover {
  background-color: rgb(66 28 40);
  color: white;
}

總結

這就是您需要了解的盒模型大部分內容。如果您將來對佈局中盒子的大小感到困惑,您可能需要回到這節課。

在下一篇文章中,我們將為您提供一些測試,您可以用來檢查您對我們提供的 CSS 盒模型資訊的理解和記憶程度。