CSS盒模型的深度思考及BFC


本文最初發表於博客園,並在GitHub上持續更新前端的系列文章。歡迎在GitHub上關注我,一起入門和進階前端。

以下是正文。

題目:談一談你對CSS盒模型的認識

專業的面試,一定會問 CSS 盒模型。對於這個題目,我們要回答一下幾個方面:

(1)基本概念:content、padding、margin。

(2)標准盒模型、IE盒模型的區別。不要漏說了IE盒模型,通過這個問題,可以篩選一部分人。

(3)CSS如何設置這兩種模型(即:如何設置某個盒子為其中一個模型)?如果回答了上面的第二條,還會繼續追問這一條。

(4)JS如何設置、獲取盒模型對應的寬和高?這一步,已經有很多人答不上來了。

(5)實例題:根據盒模型解釋邊距重疊

前四個方面是逐漸遞增,第五個方面,卻鮮有人知。

(6)BFC(邊距重疊解決方案)或IFC。

如果能回答第五條,就會引出第六條。BFC是面試頻率較高的。

總結:以上幾點,從上到下,知識點逐漸遞增,知識面從理論、CSS、JS,又回到CSS理論。

接下來,我們把上面的六條,依次講解。

標准盒模型和IE盒子模型

標准盒子模型:

IE盒子模型:

上圖顯示:

在 CSS 盒子模型 (Box Model) 規定了元素處理元素的幾種方式:

  • width和height:內容的寬度、高度(不是盒子的寬度、高度)。
  • padding:內邊距。
  • border:邊框。
  • margin:外邊距。

CSS盒模型和IE盒模型的區別:

  • 標准盒子模型中,width 和 height 指的是內容區域的寬度和高度。增加內邊距、邊框和外邊距不會影響內容區域的尺寸,但是會增加元素框的總尺寸。

  • IE盒子模型中,width 和 height 指的是內容區域+border+padding的寬度和高度。

CSS如何設置這兩種模型

代碼如下:

    /* 設置當前盒子為 標准盒模型(默認) */
    box-sizing: content-box;

    /* 設置當前盒子為 IE盒模型 */
    box-sizing: border-box;

備注:盒子默認為標准盒模型。

JS如何設置、獲取盒模型對應的寬和高

方式一:通過DOM節點的 style 樣式獲取

	element.style.width/height;

缺點:通過這種方式,只能獲取行內樣式,不能獲取內嵌的樣式和外鏈的樣式。

這種方式有局限性,但應該了解。

方式二(IE獨有的)

	element.currentStyle.width/height;

獲取到的即時運行完之后的寬高(三種css樣式都可以獲取)。但這種方式只有IE獨有。

方式三(通用型)

	window.getComputedStyle(element).width/height;

方式三和方式二一樣。只不過,方式三能兼容 Chrome、火狐。是通用型方式。

方式4

	element.getBoundingClientRect().width/height;

此 api 的作用是:獲取一個元素的絕對位置。絕對位置是視窗 viewport 左上角的絕對位置。

此 api 可以拿到四個屬性:left、top、width、height。

總結:

上面的四種方式,要求能說出來區別,以及哪個的通用型更強。

margin塌陷/margin重疊

標准文檔流中,豎直方向的margin不疊加,只取較大的值作為margin(水平方向的margin是可以疊加的,即水平方向沒有塌陷現象)。

PS:如果不在標准流,比如盒子都浮動了,那么兩個盒子之間是沒有margin重疊的現象的。

我們來看幾個例子。

兄弟元素之間

如下圖所示:

子元素和父元素之間

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <style>

        * {
            margin: 0;
            padding: 0;
        }

        .father {
            background: green;

        }

        /* 給兒子設置margin-top為10像素 */
        .son {
            height: 100px;
            margin-top: 10px;
            background: red;
        }

    </style>
</head>
<body>
<div class="father">
    <div class="son"></div>
</div>
</body>
</html>

上面的代碼中,兒子的height是 100px,magin-top 是10px。注意,此時父親的 height 是100,而不是110。因為兒子和父親在豎直方向上,共一個margin。

兒子這個盒子:

父親這個盒子:

上方代碼中,如果我們給父親設置一個屬性:overflow: hidden,就可以避免這個問題,此時父親的高度是110px,這個用到的就是BFC(下一段講解)。

善於使用父親的padding,而不是兒子的margin

其實,這一小段講的內容與上一小段相同,都是講父子之間的margin重疊。

我們來看一個奇怪的現象。現在有下面這樣一個結構:(div中放一個p)

	<div>
		<p></p>
	</div>

上面的結構中,我們嘗試通過給兒子p一個margin-top:50px;的屬性,讓其與父親保持50px的上邊距。結果卻看到了下面的奇怪的現象:

此時我們給父親div加一個border屬性,就正常了:

如果父親沒有border,那么兒子的margin實際上踹的是“流”,踹的是這“行”。所以,父親整體也掉下來了。

margin這個屬性,本質上描述的是兄弟和兄弟之間的距離; 最好不要用這個marign表達父子之間的距離。

所以,如果要表達父子之間的距離,我們一定要善於使用父親的padding,而不是兒子的margin。

BFC(邊距重疊解決方案)

BFC的概念

BFC(Block Formatting Context):塊級格式化上下文。你可以把它理解成一個獨立的區域。

另外還有個概念叫IFC。不過,BFC問得更多。

BFC 的原理/BFC的布局規則【非常重要】

BFC 的原理,其實也就是 BFC 的渲染規則(能說出以下四點就夠了)。包括:

  • (1)BFC 里面的元素,在垂直方向,邊距會發生重疊

  • (2)BFC在頁面中是獨立的容器,外面的元素不會影響里面的元素,反之亦然。(稍后看舉例1

  • (3)BFC區域不與旁邊的float box區域重疊。(可以用來清除浮動帶來的影響)。(稍后看舉例2

  • (4)計算BFC的高度時,浮動的子元素也參與計算。(稍后看舉例3

如何生成BFC

有以下幾種方法:

  • 方法1:overflow: 不為vidible,可以讓屬性是 hidden、auto。【最常用】

  • 方法2:浮動中:float的屬性值不為none。意思是,只要設置了浮動,當前元素就創建了BFC。

  • 方法3:定位中:只要posiiton的值不是 static或者是relative即可,可以是absolutefixed,也就生成了一個BFC。

  • 方法4:display為inline-block, table-cell, table-caption, flex, inline-flex

參考鏈接:

下面來看幾個例子,看看如何生成BFC。

BFC 的應用

舉例1:解決 margin 重疊

當父元素和子元素發生 margin 重疊時,解決辦法:給子元素增加一個父元素,給這個父元素創建BFC

比如說,針對下面這樣一個 div 結構:

<div class="father">
    <p class="son">
    </p>
</div>

上面的div結構中,如果父元素和子元素發生margin重疊,我們可以給子元素創建一個 BFC,就解決了:

<div class="father">
    <p class="son" style="overflow: hidden">
    </p>
</div>

因為第二條:BFC區域是一個獨立的區域,不會影響外面的元素

舉例2:BFC區域不與float區域重疊:

針對下面這樣一個div結構;

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <style>

        .father-layout {
            background: pink;
        }

        .father-layout .left {
            float: left;
            width: 100px;
            height: 100px;
            background: green;
        }

        .father-layout .right {
            height: 150px;  /*右側標准流里的元素,比左側浮動的元素要高*/
            background: red;
        }

    </style>
</head>
<body>

<section class="father-layout">
    <div class="left">
        左側,生命壹號
    </div>
    <div class="right">
        右側,smyhvae,smyhvae,smyhvae,smyhvae,smyhvae,smyhvae,smyhvae,smyhvae,smyhvae,smyhvae,smyhvae,smyhvae,
    </div>
</section>

</body>
</html>

效果如下:

上圖中,由於右側標准流里的元素,比左側浮動的元素要高,導致右側有一部分會跑到左邊的下面去。

如果要解決這個問題,可以將右側的元素創建BFC,因為第三條:BFC區域不與float box區域重疊。解決辦法如下:(將right區域添加overflow屬性)

    <div class="right" style="overflow: hidden">
        右側,smyhvae,smyhvae,smyhvae,smyhvae,smyhvae,smyhvae,smyhvae,smyhvae,smyhvae,smyhvae,smyhvae,smyhvae,
    </div>

上圖表明,解決之后,father-layout的背景色顯現出來了,說明問題解決了。

舉例3:清除浮動

現在有下面這樣的結構:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <style>

        .father {
            background: pink;
        }

        .son {
            float: left;
            background: green;
        }

    </style>
</head>
<body>

<section class="father">
    <div class="son">
        生命壹號
    </div>

</section>
</body>
</html>

效果如下:

上面的代碼中,兒子浮動了,但由於父親沒有設置高度,導致看不到父親的背景色(此時父親的高度為0)。正所謂有高度的盒子,才能關住浮動

如果想要清除浮動帶來的影響,方法一是給父親設置高度,然后采用隔牆法。方法二是 BFC:給父親增加 overflow=hidden屬性即可, 增加之后,效果如下:

為什么父元素成為BFC之后,就有了高度呢?這就回到了第四條:計算BFC的高度時,浮動元素也參與計算。意思是,在計算BFC的高度時,子元素的float box也會參與計算

我的公眾號

想學習代碼之外的軟技能?不妨關注我的微信公眾號:生命團隊(id:vitateam)。

掃一掃,你將發現另一個全新的世界,而這將是一場美麗的意外:






免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM