佈局和包含塊

元素的大小和位置通常會受到其**包含塊**的影響。大多數情況下,包含塊是元素最近的**塊級**祖先的**內容區域**,但這並非總是如此。在本文中,我們將探討確定元素包含塊的因素。

當用戶代理(如您的瀏覽器)佈局文件時,它會為每個元素生成一個盒子。每個盒子被分成四個區域

  1. 內容區域
  2. 填充區域
  3. 邊框區域
  4. 外邊距區域

Diagram of the box model

許多開發人員認為元素的包含塊始終是其父元素的內容區域,但這並不一定正確。讓我們研究一下決定元素包含塊的因素。

包含塊的影響

在瞭解是什麼決定了元素的包含塊之前,瞭解它為什麼重要是有幫助的。

元素的大小和位置通常會受到其包含塊的影響。應用於絕對定位元素的**width**、**height**、**padding**、**margin**和偏移屬性的百分比值(即其**position**設定為**absolute**或**fixed**)是根據元素的包含塊計算的。

識別包含塊

識別包含塊的過程完全取決於元素的**position**屬性的值

  1. 如果**position**屬性是**static**、**relative**或**sticky**,則包含塊由最近祖先元素的內容框邊緣形成,該祖先元素要麼是**塊級容器**(例如內聯塊、塊或列表項元素),要麼**建立格式化上下文**(例如表格容器、flex 容器、網格容器或塊級容器本身)。
  2. 如果**position**屬性是**absolute**,則包含塊由最近祖先元素的填充框邊緣形成,該祖先元素的**position**值不為**static**(**fixed**、**absolute**、**relative**或**sticky**)。
  3. 如果**position**屬性是**fixed**,則包含塊由**視窗**(在連續媒體的情況下)或頁面區域(在分頁媒體的情況下)建立。
  4. 如果**position**屬性是**absolute**或**fixed**,則包含塊也可以由最近祖先元素的填充框邊緣形成,該祖先元素具有以下任何屬性
    • **filter**、**backdrop-filter**、**transform**或**perspective**值不為**none**。
    • contain 屬性的值為 layoutpaintstrictcontent(例如 contain: paint;)時。
    • container-type 屬性的值不為 normal 時。
    • will-change 屬性的值包含一個屬性,該屬性的非初始值會形成包含塊(例如 filtertransform)時。
    • content-visibility 屬性的值為 auto 時。

注意: 根元素(<html>)所在的包含塊是一個稱為初始包含塊的矩形。它的尺寸與視窗(對於連續媒體)或頁面區域(對於分頁媒體)的尺寸相同。

注意: 瀏覽器在 perspectivefilter 屬性是否參與形成包含塊方面存在不一致。

從包含塊計算百分比值

如上所述,當某些屬性被賦予百分比值時,計算值取決於元素的包含塊。以這種方式工作的屬性是盒模型屬性偏移屬性

  1. heighttopbottom 屬性根據包含塊的 height 計算百分比值。
  2. widthleftrightpaddingmargin 屬性根據包含塊的 width 計算百分比值。

注意: 一個塊級容器(例如內聯塊、塊級或列表項元素)要麼只包含參與內聯格式化上下文的內聯級盒子,要麼只包含參與塊級格式化上下文的塊級盒子。一個元素只有在它包含塊級盒子或內聯級盒子時才是一個塊級容器。

一些示例

我們所有示例的 HTML 程式碼如下:

html
<body>
  <section>
    <p>This is a paragraph!</p>
  </section>
</body>

以下每個示例中只更改 CSS。

示例 1

在本例中,段落是靜態定位的,因此它的包含塊是 <section>,因為它是最接近的祖先,並且是一個塊級容器(由於 display: block)。

css
body {
  background: beige;
}

section {
  display: block;
  width: 400px;
  height: 160px;
  background: lightgray;
}

p {
  width: 50%; /* == 400px * .5 = 200px */
  height: 25%; /* == 160px * .25 = 40px */
  margin: 5%; /* == 400px * .05 = 20px */
  padding: 5%; /* == 400px * .05 = 20px */
  background: cyan;
}

示例 2

在本例中,段落的包含塊是 <body> 元素,因為 <section> 不是一個塊級容器(由於 display: inline),並且沒有建立格式化上下文。

css
body {
  background: beige;
}

section {
  display: inline;
  background: lightgray;
}

p {
  width: 50%; /* == half the body's width */
  height: 200px; /* Note: a percentage would be 0 */
  background: cyan;
}

示例 3

在本例中,段落的包含塊是 <section>,因為後者的 positionabsolute。段落的百分比值受其包含塊的 padding 影響,但是如果包含塊的 box-sizing 值為 border-box,則不會發生這種情況。

css
body {
  background: beige;
}

section {
  position: absolute;
  left: 30px;
  top: 30px;
  width: 400px;
  height: 160px;
  padding: 30px 20px;
  background: lightgray;
}

p {
  position: absolute;
  width: 50%; /* == (400px + 20px + 20px) * .5 = 220px */
  height: 25%; /* == (160px + 30px + 30px) * .25 = 55px */
  margin: 5%; /* == (400px + 20px + 20px) * .05 = 22px */
  padding: 5%; /* == (400px + 20px + 20px) * .05 = 22px */
  background: cyan;
}

示例 4

在本例中,段落的 positionfixed,因此它的包含塊是初始包含塊(在螢幕上,是視窗)。因此,段落的尺寸會根據瀏覽器視窗的大小而變化。

css
body {
  background: beige;
}

section {
  width: 400px;
  height: 480px;
  margin: 30px;
  padding: 15px;
  background: lightgray;
}

p {
  position: fixed;
  width: 50%; /* == (50vw - (width of vertical scrollbar)) */
  height: 50%; /* == (50vh - (height of horizontal scrollbar)) */
  margin: 5%; /* == (5vw - (width of vertical scrollbar)) */
  padding: 5%; /* == (5vw - (width of vertical scrollbar)) */
  background: cyan;
}

示例 5

在本例中,段落的 positionabsolute,因此它的包含塊是 <section>,它是具有非 nonetransform 屬性的最接近的祖先。

css
body {
  background: beige;
}

section {
  transform: rotate(0deg);
  width: 400px;
  height: 160px;
  background: lightgray;
}

p {
  position: absolute;
  left: 80px;
  top: 30px;
  width: 50%; /* == 200px */
  height: 25%; /* == 40px */
  margin: 5%; /* == 20px */
  padding: 5%; /* == 20px */
  background: cyan;
}

另請參閱