盒子模型

CSS 中的所有內容都包含在一個框中,理解這些框是能夠使用 CSS 建立更復雜的佈局或將專案與其他專案對齊的關鍵。在本課中,我們將瞭解 CSS 盒子模型。您將瞭解其工作原理以及相關的術語。

先決條件 已安裝基本軟體,瞭解檔案處理的基本知識,HTML 基礎知識(學習HTML 簡介),以及對 CSS 工作原理的瞭解(學習CSS 入門)。
目標 瞭解 CSS 盒子模型,構成盒子模型的元素以及如何切換到備用模型。

塊級盒子和內聯盒子

在 CSS 中,我們有幾種型別的盒子,通常分為塊級盒子內聯盒子。型別指的是盒子在頁面流中以及相對於頁面上其他盒子的行為方式。盒子具有內部顯示型別外部顯示型別

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

外部顯示型別

如果盒子的外部顯示型別為block,那麼

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

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

如果盒子的外部顯示型別為inline,那麼

  • 該盒子將不會換行。
  • widthheight屬性將不適用。
  • 頂部和底部填充、邊距和邊框將適用,但不會導致其他內聯盒子遠離該盒子。
  • 左側和右側填充、邊距和邊框將適用,並將導致其他內聯盒子遠離該盒子。

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

內部顯示型別

盒子還具有內部顯示型別,它決定該盒子內部的元素如何排列。

塊級和內聯佈局是網頁上內容預設的行為方式。預設情況下,如果沒有其他指令,盒子內的元素也會以正常流方式排列,並表現為塊級或內聯盒子。

例如,您可以透過設定display: flex;來更改內部顯示型別。該元素將繼續使用外部顯示型別block,但這會將內部顯示型別更改為flex。該盒子的所有直接子元素將成為彈性專案,並根據Flexbox規範進行操作。

當您繼續學習有關 CSS 佈局的更多詳細資訊時,您將遇到flex,以及盒子的各種其他內部值,例如grid

注意:要了解更多關於 display 的值以及盒子在塊級和內聯佈局中的工作方式,請檢視 MDN 指南塊級和內聯佈局

不同顯示型別的示例

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

  • 一個添加了 CSS 邊框的段落。瀏覽器將其呈現為塊級盒子。段落從新行開始,並擴充套件到整個可用寬度。
  • 一個列表,它使用display: flex進行佈局。這為容器的子元素(即彈性專案)建立了彈性佈局。列表本身是一個塊級盒子,與段落一樣,擴充套件到整個容器寬度,並在新行換行。
  • 一個塊級段落,其中包含兩個<span>元素。這些元素通常是inline,但是,其中一個元素具有類名 "block",它被設定為display: block

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

  • 第一個段落中的<span>元素預設是內聯的,因此不會強制換行。
  • 設定為display: inline-flex<ul>元素建立一個包含一些彈性專案的內聯盒子。
  • 這兩個段落都被設定為display: inline。內聯彈性容器和段落都在一行上執行,而不是換行(如果它們作為塊級元素顯示,則會換行)。

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

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

什麼是 CSS 盒子模型?

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

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

盒子的組成部分

構成 CSS 中的塊級盒子的是

  • 內容盒子:顯示內容的區域;使用像inline-sizeblock-sizewidthheight這樣的屬性對其進行大小調整。
  • 填充盒子:填充作為空白空間位於內容周圍;使用padding及其相關屬性對其進行大小調整。
  • 邊框盒子:邊框盒子包裹內容和任何填充;使用border及其相關屬性對其進行大小調整。
  • 邊距盒子:邊距是最外層,包裹內容、填充和邊框,作為該盒子與其他元素之間的空白空間;使用margin及其相關屬性對其進行大小調整。

下圖顯示了這些層

Diagram of the box model

標準 CSS 盒子模型

在標準盒子模型中,如果您在盒子中設定inline-sizeblock-size(或widthheight)屬性值,這些值將定義內容盒子inline-sizeblock-size(在水平語言中為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;
  inline-size: 350px;
  height: 150px;
  block-size: 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。唯一的區別是第二個盒子被設定為使用備用盒子模型。

您可以更改第二個盒子的大小(透過將 CSS 新增到.alternate類中)使其在寬度和高度上與第一個盒子匹配嗎?

注意:您可以在此處找到此任務的解決方案。

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

您的瀏覽器開發者工具可以使理解盒子模型變得更加容易。如果您在 Firefox 的開發者工具中檢查元素,您可以看到元素的大小及其邊距、填充和邊框。以這種方式檢查元素是瞭解您的盒子是否真的如您所想的那樣大小的絕佳方法!

Inspecting the box model of an element using Firefox DevTools

邊距、填充和邊框

您已經看到上面的示例中使用的marginpaddingborder屬性。這些示例中使用的屬性是簡寫,使我們能夠一次設定盒子的所有四個邊。這些簡寫也具有等效的完整屬性,它們允許單獨控制盒子的不同邊。

讓我們更詳細地瞭解這些屬性。

邊距

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

我們可以使用margin屬性一次控制元素的所有邊距,或者使用等效的完整屬性分別控制每個邊

在以下示例中,嘗試更改邊距值以檢視盒子如何由於邊距建立或移除空間(如果是負邊距)而被推到周圍,在該元素與其包含元素之間建立或移除空間。

邊距摺疊

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

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

在下面的例子中,我們有兩個段落。頂部的段落有一個margin-bottom為50畫素,另一個段落有一個margin-top為30畫素。這些邊距合併在一起,因此盒子之間的實際邊距是50畫素,而不是兩個邊距的總和。

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

許多規則決定了何時邊距會合並或不會合並。有關更多資訊,請參閱有關掌握邊距合併的詳細頁面。需要記住的最重要的一點是,如果使用邊距建立空間,但沒有獲得預期的空間,則會發生邊距合併。

邊框

邊框繪製在盒子的邊距和填充之間。如果你使用的是標準盒子模型,邊框的大小將新增到內容盒子的widthheight中。如果你使用的是備用盒子模型,那麼邊框越大,內容盒就越小,因為邊框會佔用元素盒子可用widthheight的一部分。

對於樣式化邊框,有很多屬性——有四個邊框,每個邊框都有一個樣式、寬度和顏色,我們可能需要操作。

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

要分別設定每個邊的屬性,請使用

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

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

在下面的例子中,我們使用了各種簡寫和長手來建立邊框。嘗試使用不同的屬性,確保你理解它們的工作原理。邊框屬性的MDN頁面提供了有關不同可用邊框樣式的資訊。

填充

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

padding屬性控制元素所有邊的填充。要分別控制每邊,請使用這些長手屬性

在下面的例子中,你可以更改類.box上的填充值,以檢視這會如何改變文字相對於盒子的起始位置。你也可以更改類.container上的填充,在容器和盒子之間建立空間。你可以更改任何元素上的填充,在元素的邊框與其內部的內容之間建立空間。

盒子模型和內聯盒子

以上所有內容都完全適用於塊盒子。一些屬性也可能適用於內聯盒子,例如由<span>元素建立的那些。

在下面的例子中,我們有一個<span>在段落內。我們對其應用了widthheightmarginborderpadding。你可以看到寬度和高度被忽略了。頂部和底部的邊距、填充和邊框被尊重,但不會改變其他內容與內聯盒子的關係。填充和邊框與段落中的其他單詞重疊。左右填充、邊距和邊框會將其他內容從盒子中移開。

使用 display: inline-block

display: inline-blockdisplay的一個特殊值,它提供了inlineblock之間的中間地帶。如果你不希望專案換行,但希望它尊重widthheight,並避免上述重疊,請使用它。

具有display: inline-block的元素執行我們已經知道的一些塊操作

  • widthheight屬性被尊重。
  • paddingmarginborder會導致其他元素被推離盒子。

但是,它不會換行,並且只有在你顯式新增widthheight屬性時才會變得比其內容更大。

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

當你想透過新增padding來使連結具有更大的點選區域時,這將非常有用。<a>是一個內聯元素,類似於<span>;你可以使用display: inline-block來允許對其設定填充,從而使使用者更容易點選連結。

你經常在導航欄中看到這種方式。下面的導航使用flexbox在一行中顯示,並且我們已向<a>元素添加了填充,因為我們希望能夠在滑鼠懸停在<a>上時更改background-color。填充似乎與<ul>元素上的邊框重疊。這是因為<a>是一個內聯元素。

display: inline-block新增到具有.links-list a選擇器的規則中,你將看到它如何透過使其他元素尊重填充來解決這個問題。

測試您的技能!

你已經閱讀完本文的結尾,但你能記住最重要的資訊嗎?在你繼續之前,你可以找到一些進一步的測試來驗證你是否保留了這些資訊——請參閱測試你的技能:盒子模型.

總結

這些就是你關於盒子模型需要了解的大部分內容。如果你發現自己在佈局中對盒子的大小感到困惑,你將來可能需要返回本課。

在下一篇文章中,我們將介紹如何使用背景和邊框使你的普通盒子看起來更有趣。