Css規範整理:3.2、常規流佈局:塊格式化上下文

李一花發表於2018-07-23

常規流佈局

塊格式化上下文

其中關鍵概念有:

  • 塊級盒(block level box):參與塊格式化上下文的盒,即outer display type 為 block。
  • 塊容器盒(block container box):可以建立塊格式化上下文 的容器。
  • 塊盒(block box):作為塊容器的塊級盒。

何時建立新的塊級格式化上下文:

  • 浮動盒
  • 絕對定位元素
  • 非塊盒的塊容器(flow-root):inline-blocks、table-cells、table-captions
  • overflow不為visible

佈局方式:

豎直方向:

在一個塊格式化上下文中,盒在豎直方向上,從包含塊頂部一個接一個放置。兩個兄弟盒之間的豎直距離由margin決定。同一個塊格式化上下文中的相鄰塊級盒之間的豎直margin會合並。

在一個塊格式化上下文中,盒在垂直方向一個接一個地放置,從包含塊的頂部開始。兩個兄弟盒之間的垂直距離由margin屬性決定。同一個塊格式化上下文中的相鄰塊級盒之間的垂直外邊距會合並。(margin 合併相關知識在佈局介紹完之後再介紹)

  <style>
        .main {
            width: 500px;
            height:500px;
            background: #008000;
            border:1px solid red;
        }
        .main > section {
            background: red;
            height: 100px;
            margin-top:10px;
            margin-bottom:10px;
        }
        .main > div {
            background: yellow;
            height:200px;
            margin-top:20px;
        }
    </style>
    <div class="main">
        <section>塊級盒1</section>
        <div>塊級盒2</div>
    </div>

垂直方向上的 margin 控制塊級盒垂直方向上的距離。

水平方向:

在一個塊格式化上下文中,每個盒的左外邊界(left outer edge)挨著包含塊的左外邊界(對於從右向左的格式化,右外邊界挨著),即使存在浮動(儘管一個盒的行框可能會因為浮動而收縮 譯註:環繞浮動元素放置的行框比正常的行短一些),這也成立。

除非該盒建立了一個新的塊格式化上下文(這種情況下,該盒自身可能會因為浮動變窄)

<style>
    body{
        direction:rtl
    }
    .fl{
        float: right;
        height:120px;
        width:100px;
        border: yellow 5px solid;
        color: blue
    }
    .main{
        height:500px;
        background: #008000;
    }
    .content{
        border: red 10px solid;
          height:100px;
    }
    .content2{
        border: purple 10px solid;
          height:100px;
    }
</style>
<div>
    <div class="main">
        <span class="fl">浮動盒內容</span>
        <div class="content">content塊級盒內容
             <span class="fl" style="border-color:orange">內部浮動盒內容</span>
        </div>

        <span class="fl">浮動盒內容</span>
        <div class="content2" style="overflow:hidden">
          	content2塊級盒內容 
             <span class="fl" style="border-color:orange">內部浮動盒內容</span>
        </div>
    </div>
</div>

  1. 以上程式碼,改變了格式化方向(direction:rtl),所以塊級盒右邊界對齊,左邊界允許溢位。
  2. 上述程式碼的塊級盒 content,在流內(即 inner display type = flow)塊級盒右邊界對齊,內部行盒寬度因浮動收縮,但塊級盒本身寬度不變
  3. 上述程式碼的塊級盒 content2,因為設定了overflow不為visible ,所以建立了新的格式化上下文,因此該盒因浮動變窄,外部浮動盒不能影響該塊級盒的行盒,內部浮動盒溢位部分被隱藏(隱藏是overflow:hidden的作用)

Margin 合併:

同一個塊格式化上下文中的相鄰塊級盒之間的垂直外邊距會合並。

以下是規範的內容(可忽略):

CSS中,兩個或多個盒(可能但不一定是兄弟)的相鄰的margin會被結合成一個margin。外邊距按這種方式結合叫做合併(collapse),產生的結合的外邊距叫做摺疊外邊距(collapsed margin 譯註:這裡譯作摺疊表示結果,與合併的動作區分開)

相鄰的垂直外邊距會合並,除了:

水平margin不會合並

兩個margin是相鄰的,當且僅當:

  • 都屬於流內(in-flow)塊級盒,處於同一個塊格式化上下文
  • 沒有行框(line box),空隙,內邊距和邊框把它們隔開(注意,因此某些0高度行框(見9.4.2)會被忽略)
  • 都屬於垂直相鄰框邊界(vertically-adjacent box edges),即形成下列某一對:
  • 盒的上邊距與其第一個流內(in-flow)孩子的上邊距
  • 盒的下邊距與其下一個流內緊挨著的兄弟的上邊距
  • 最後一個流內孩子的下邊距與其height計算值為`auto`的父元素的下邊距
  • 盒的上邊距和下邊距,要求該盒沒有建立新的塊格式化上下文,並且`min-height`計算值為0,`height`計算值為0或`auto`,還沒有流內孩子

摺疊外邊距也能與另一個外邊距相鄰,只要其外邊距的任意一部分與那個外邊距相鄰就算

注意 相鄰外邊距也可以由不具兄弟或祖先關係的元素生成

注意 上面的規則表明:

  • 浮動的盒與任何其它盒之間的margin不會合並(甚至一個浮動盒與它的流內子級之間也不會)
  • 建立了新的塊格式化上下文的元素(例如,浮動盒與`overflow`不為`visible`的元素)的margin不會與它們的流內孩子合併
  • 絕對定位的盒的margin不會合並(甚至與它們的流內子級也不會)
  • inline-block盒的margin不會合並(甚至與它們的流內子級也不會)
  • 流內塊級元素的bottom margin總會與它的下一個流內塊級兄弟的top margin合併,除非該兄弟(元素)具有間隙
  • 流內塊級元素的top margin會與它的第一個流內塊級子級的top margin合併,條件是該元素沒有上邊框和上內邊距,並且其孩子不具有間隙
  • 一個`height`為`auto`並且`min-height`為0的流內塊級盒的bottom margin會與它的最後一個流內塊級子級的bottom margin合併,條件是該盒沒有下內邊距和下邊框,並且其孩子的下外邊距沒有與具有間隙的上外邊距合併
  • 盒自身的外邊距也會合並,條件是`min-height`屬性為0,既沒有上下邊框,也沒有上下內邊距,`height`為0或`auto`,且不含行框的話,那麼其所有流內孩子的外邊距(如果存在的話)都會合並

當兩個或者更多的margin合併時,產生的margin寬度為被合併的外邊距寬度中的最大值。至於負margin,就從正相鄰margin的最大值中減去負相鄰margin的絕對值的最大值。如果沒有正margin,就用0減去相鄰margin的絕對值的最大值

如果盒的上下外邊距相鄰,那麼外邊距合併時可能會穿過它(it is possible for margins to collapse through it)。這種情況下,該元素的位置取決於它與其它外邊距被合併了的元素的關係

  • 如果該元素的外邊距與其父元素的上外邊距合併了,盒的上邊框邊界被定義為與其父元素的相同
  • 否則,要麼該元素的父元素沒參與外邊距合併,要麼只涉及其父元素的下外邊距。該元素上邊框邊界的位置與元素下邊框非0時的位置相同

注意,被摺疊外邊距穿過的元素的位置不影響其它外邊距正要被合併的元素的位置,其上邊框邊界的位置僅用於佈局這些元素的後代元素

⭐要點

  • 同一個塊格式化上下文:因此建立了 新的塊格式化上下文的該盒 不與任何盒合併
    • 根元素的margin 不合並(<html></html>)
    • 浮動的盒與任何其它盒之間的margin不會合並(一個浮動盒與它的流內子級之間也不會)
    • 絕對定位的盒的margin不會合並(與它們的流內子級也不會)
    • 非塊盒的塊容器(flow-root):inline-block、table-cells、table-captions
      • inline-block盒的margin不會合並(與它們的流內子級也不會)
    • overflow不為visible
  • 相鄰:margin 之間有間隔 就不可以進行合併。相鄰一詞沒有考慮元素之間的關係,考慮的是margin 的位置關係
    • 沒有行框(line box),空隙,內邊距和邊框把它們隔開。
  • 塊級盒:行內級不可以。
  • 垂直:margin left 和 margin right 不受影響。

例子:(不完全展示上述的可能性,)

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <style>
        html {
            margin: 8px 0;
            /* 根元素上的margin 不合並*/
        }

        body {
            margin: 8px;
            /** 
             * 設定這個的原因是因為希望塊級有內容的時候不是由字型撐起來內容的高度,
             * 是以行高撐起內容的高度,
             * 目的以方便計算margin的高度
             **/
            font-size: 12px;
            /**確定字型的大小**/
            line-height: 20px;
            /** 保證行高大於字型的大小**/
        }

        .div {
            margin: 10px 0;
        }
    </style>
</head>
<!-- margin-top:8px 不合並 -->
<body>
    <!-- margin-top:10px -->
    <div class="div" style="overflow:auto;"><!-- 建立新的格式化上下文 -->
        <!-- margin-top:10px 不合並 -->
        <div class="div">
            div內容<!-- line-height:20px -->
        </div>
        <!-- margin-bottom:10px 不合並 -->
    </div>
    <!-- margin-bottom:10px -->
    body內容<!-- line-height:20px -->

    <div class="div"></div>
</body><!-- margin top 與 bottom:10px 與 body margin-bottom:8px 合併 = margin-bottom:10px -->

</html>

規範是錯誤的:空隙(clearance)並不能阻止margin 合併。


<style>
    body {
        direction: rtl
    }

    .fl {
        float: right;
        height: 120px;
        width: 100px;
        border: yellow 5px solid;
        color: blue
    }

    .main {
        height: 500px;
        background: yellowgreen;
        position: relative;
    }

    .content {
        border: red 10px solid;
        height: 100px;
        margin-bottom:100px;
    }

    .content2 {
        clear: both;
        border: purple 10px solid;
        height: 100px;
        margin-top:120px;
    }
</style>
<div>
    <div class="main">
        <span class="fl">浮動盒內容</span>
        <div class="content">content塊級盒內容
            <span class="fl" style="border-color:orange">內部浮動盒內容</span>
        </div>

        <div class="content2" style="overflow:auto">
            content2塊級盒內容
            <span class="fl" style="border-color:orange">內部浮動盒內容</span>
        </div>
    </div>
</div>

原文釋出時間為:2018年02月10日
原文作者:雕刻零碎 

本文來源:開源中國 如需轉載請聯絡原作者


相關文章