佈局和包含塊

一個元素的尺寸和位置通常受其包含塊的影響。大多數情況下,包含塊是該元素最近的塊級祖先元素的內容區,但情況並非總是如此。在本文中,我們將探討決定元素包含塊的因素。

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

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

Diagram of the box model

許多開發者認為,元素的包含塊總是其父元素的內容區,但這不一定正確。讓我們來研究一下決定元素包含塊的因素。

包含塊的影響

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

元素的尺寸和位置通常受其包含塊的影響。應用於元素的 widthheightpaddingmargin,以及絕對定位元素(即其 position 設定為 absolutefixed)的偏移屬性的百分比值,都是根據其包含塊計算的。

確定包含塊

確定包含塊的過程完全取決於元素 position 屬性的值:

  1. 如果 position 屬性是 staticrelativesticky,包含塊由最近的祖先元素的內容盒(content box)的邊緣構成,該祖先元素要麼是塊容器(例如 inline-block、block 或 list-item 元素),要麼建立了格式化上下文(例如 table 容器、flex 容器、grid 容器或塊容器本身)。
  2. 如果 position 屬性是 absolute,包含塊由最近的 position 值不是 static(即 fixedabsoluterelativesticky)的祖先元素的內邊距盒(padding box)的邊緣構成。
  3. 如果 position 屬性是 fixed,包含塊由視口(對於連續媒體)或頁面區域(對於分頁媒體)建立。
  4. 如果 position 屬性是 absolutefixed,包含塊也可能由最近的具有以下任一屬性的祖先元素的內邊距盒(padding box)的邊緣構成:

備註: 根元素(<html>)所在的包含塊是一個被稱為初始包含塊的矩形。它的尺寸為視口(對於連續媒體)或頁面區域(對於分頁媒體)的大小。

備註:perspectivefilter 屬性對包含塊形成的影響上存在瀏覽器不一致性。

根據包含塊計算百分比值

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

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

備註: 一個塊容器(如 inline-block、block 或 list-item 元素)要麼只包含參與行內格式化上下文的行內級盒子,要麼只包含參與塊級格式化上下文的塊級盒子。一個元素只有在它包含塊級或行內級盒子時才是塊容器。

一些示例

我們所有示例的 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;
}

另見