天天看點

【前端芝士樹】詳解CSS盒模型、BFC、OffsetWidth&ClientWidth&ScrollWidth

深入了解CSS盒模型、BFC、OffsetWidth&ClientWidth&ScrollWidth

本文将從盒模型開始,一步步涉及一些常見的前端筆試和面試點

主要參考自第一篇文章,然而筆者在讀的時候未覺詳盡,便又去網上查閱了一番,擴充了其内容,希望也能給同學們提供一些參考。

下面本文章将會從以下幾個方面談談盒模型。

  • 基本概念:标準模式和怪異模式,标準模型和IE模型
  • CSS如何設定這兩種模型
  • JS如何設定擷取盒模型對應的寬和高
  • 執行個體題(根據盒模型解釋邊距重疊)
  • BFC(邊距重疊解決方案)

1.盒模型是什麼

2018搜狐前端筆試題

盒模型本質上是用以封裝HTML元素的概念盒子,它包含了邊距,邊框,填充以及實際内容。

即由外向裡是 margin, border, padding, content

2.為什麼會有兩種不同的盒模型(标準模式和怪異模式)

在了解兩種不同的盒模型之前,需要先了解一下為什麼會産生兩種不同的盒模型。

當年,Netscape4(譯注:網景公司早期的浏覽器)和IE4(微軟公司早期的浏覽器)實作CSS機制時,并沒有遵循W3C提出的标準。Netscape4 提供了糟糕的支援,而IE4 雖然接近标準,但依舊未能完全正确的支援标準。盡管IE 5 修複了IE4 許多的問題(bugs),但是依然延續CSS實作中的其它故障(主要是盒模型(box model)問題)。

然而随着标準一緻性變得越來越重要,浏覽器開發商不得不面臨一個艱難的抉擇:逐漸遵循W3C的标準是前進的方向。但是改變現有CSS的實作,完整去遵循标準,會使許多網站或多或少受到破壞。如果浏覽器突然以正确的方式解析現存的CSS,陳舊的網站顯示必然受到影響。

于是,所有的浏覽器開始提供兩種模式:

怪異模式(即相容模式 Quirks Mode/Compalibility Mode)

服務于舊式規則,

嚴格模式(即标準模式 Standard Mode/Strict Mode)

服務于标準規則。Mac平台的IE浏覽器最先實作這兩種模式,Mozilla, Safari、Opera和Windows平台的IE6也相繼實作了這兩種模式。Windows平台的IE5和Netscape4則隻提供了怪異模式。

選擇使用哪種模式需要一個觸發器,而 “DOCTYP切換” 則用于此目的。依照标準,任何一個(X)HTML文檔必須擁有一個DOCTYPE(譯注:DTD(文檔類型定義)是一組機器可讀的規則,它們訓示(X)HTML文檔中允許有什麼,不允許有什麼,DOCTYPE正是用來告訴浏覽器使用哪種DTD,一般放在(X)HTML文檔開頭聲明)用以告訴其他人這個文檔的類型風格

  1. 産生于标準化浪潮以前的網頁并沒有DOCTYPE聲明。是以'沒有DOCTYPE'意味着觸發怪異模式:既依據舊式的CSS規則渲染網頁。
  2. 相反,如果開發者明确知道包含DOCTYPE,他們應該明白他們想要怎麼做。是以大部分的DOCTYPE聲明将觸發嚴格模式:即依據标準的CSS規則渲染網頁。
  3. 任何新的或未知的DOCTYPE将觸發嚴格模式。
  4. 一些頁面依據怪異模式而寫,但是卻包含DOCTYPE。這種情況下各個浏覽器依據自己的DOCTYPE規則清單來觸發怪異模式。

所有IE的觸發 —— 在DTD聲明前加上HTML注釋

<!--Let IE into quirks mode--> 隻要在DTD聲明前加注釋或者任何标簽即可

<!DOCTYPE html>xml

對于以上兩種不同的網頁模式,産生了兩種不同的盒模型,一個是

标準模型

,一個是

IE模型

【前端芝士樹】詳解CSS盒模型、BFC、OffsetWidth&amp;ClientWidth&amp;ScrollWidth
【前端芝士樹】詳解CSS盒模型、BFC、OffsetWidth&amp;ClientWidth&amp;ScrollWidth

标準模型的寬高 = 内容(content)的寬高,

IE盒模型的寬高 = 内容(content) + 填充(padding) + 邊框(border)的總寬高。

3.通過CSS3設定兩種模型

這裡用到了

CSS3

的屬性 box-sizing

标準模型

box-sizing:content-box;

IE模型

box-sizing:border-box;

4.通過JavaScript擷取寬高

通過JS擷取盒模型對應的寬和高,有以下幾種方法:

為了友善書寫,以下用dom來表示擷取的HTML的節點。

<div class="container">
    <div id="contentBox" class="contentBox"></div>
</div>

var body = document.getElementsByClassName('container');
var dom = document.getElementById('contentBox');           

複制

1.dom.style.width/height

  這種方式隻能取到dom元素内聯樣式所設定的寬高,也就是說如果該節點的樣式是在style标簽中或外聯的CSS檔案中設定的話,通過這種方法是擷取不到dom的寬高的。

<div id="contentBox" class="contentBox" style="width: 100px;"></div>
console.log('Dom.style.width:' + dom.style.width); //100px           

複制

2.dom.currentStyle.width/height

  這種方式擷取的是在頁面渲染完成後的結果,就是說不管是哪種方式設定的樣式,都能擷取到,但這種方式隻有IE浏覽器支援。

console.log('Dom.currentStyle.width:' +  dom.currentStyle.width); //Cannot read property 'width' of undefined           

複制

3.window.getComputedStyle(dom).width/height

  這種方式的原理和2是一樣的,這個可以相容更多的浏覽器,通用性好一些。

console.log('Window.getComputedStyle(dom).width' + window.getComputedStyle(dom).width); //100px           

複制

4.dom.getBoundingClientRect().width/height

getBoundingClientRect 用于擷取某個元素相對于視窗的位置集合

通過計算元素的位置,來擷取對應的寬高

console.log('Dom.getBoundingClientRect().width: ' + dom.getBoundingClientRect().width); //160           

複制

5.dom.offsetWidth/offsetHeight

對象所在元素的實際寬度

console.log('Dom.offsetWidth: ' + dom.offsetWidth); //160           

複制

具體情況如圖所示

其中,盒模型為标準模型,元素内容寬度為100px, padding寬度為10px,border寬度為20px, margin寬度為30px

【前端芝士樹】詳解CSS盒模型、BFC、OffsetWidth&amp;ClientWidth&amp;ScrollWidth

5.DOM屬性之 OffsetWidth / ClientWidth / ScrollWidth

6.邊距重疊

什麼是邊距重疊

如下圖,父元素沒有設定margin-top,而子元素設定了margin-top:20px;可以看出,父元素也一起有了邊距。

【前端芝士樹】詳解CSS盒模型、BFC、OffsetWidth&amp;ClientWidth&amp;ScrollWidth
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <style>
        *{
            margin:0;
            padding:0;
        }
        .demo{
            height:100px;
            background: #eee;
        }
        .parent{
            height:200px;
            background: #88f;
        }
        .child{
            height:100px;
            margin-top:20px;
            background: #0ff;
            width:200px;
        }
    </style>
</head>
<body>
    <section class="demo">
        <h2>此部分是能更容易看出讓下面的塊的margin-top。</h2>
    </section>
    <section class = "parent">
        <article class="child">
            <h2>子元素</h2>
            margin-top:20px;
        </article>
        <h2>父元素</h2>
            沒有設定margin-top
    </section>
</body>
</html>           

複制

7.邊距重疊解決方案(BFC)

首先要明确BFC是什麼意思,其全英文拼寫為 Block Formatting Context 直譯為“塊級格式化上下文”

BFC的原理

  • 内部的box會在垂直方向,一個接一個的放置 每個元素的margin box的左邊,與包含塊border
  • box的左邊相接觸(對于從做往右的格式化,否則相反)
  • box垂直方向的距離由margin決定,屬于同一個bfc的兩個相鄰box的margin會發生重疊 bfc的區域不會與浮動區域的box重疊
  • bfc是一個頁面上的獨立的容器,外面的元素不會影響bfc裡的元素,反過來,裡面的也不會影響外面的
  • 計算bfc高度的時候,浮動元素也會參與計算

怎麼去建立BFC

  • float屬性不為none(脫離文檔流)
  • position為absolute或fixed
  • display為inline-block,table-cell,table-caption,flex,inine-flex
  • overflow設定為scroll/hidden/overlay/auto
  • 根元素

應用場景

  1. 自适應兩欄布局
  2. 清除内部浮動
  3. 防止垂直margin重疊

看一個垂直margin重疊例子

<div class="container">
    <div class="backgroundDom">
        <div class="top">&nbsp;Top margin-bottom: 30px</div>
        <div class="bottom">&nbsp;Bottom margin-top: 50px</div>
    </div>
</div>

.top{
    margin-bottom:30px;
}
.bottom{
    margin-top: 50px;
}
.top, .bottom{
    width: 100%;
    height: 100px;
    line-height: 100px;
    background: cornflowerblue;
}            

複制

效果圖

【前端芝士樹】詳解CSS盒模型、BFC、OffsetWidth&amp;ClientWidth&amp;ScrollWidth

用BFC可以解決垂直margin重疊的問題

方法一 采用float或者position設定為absolute/fixed 脫離文檔流

float: left;
position: absolute;// 或者fixed           

複制

方法二 設定display為inline-block,table-cell,table-caption,flex,inine-flex

display: inline-block;           

複制

【前端芝士樹】詳解CSS盒模型、BFC、OffsetWidth&amp;ClientWidth&amp;ScrollWidth

方法三 添加一個父元素包裹,并設定overflow為scroll/hidden/overlay/auto

<div class="container">
    <div class="backgroundDom">
        <div class="top">&nbsp;Top margin-bottom: 30px</div>
        <div style="overflow: hidden">
            <div class="bottom">&nbsp;Bottom margin-top: 50px</div>
        </div>
    </div>
</div>           

複制

【前端芝士樹】詳解CSS盒模型、BFC、OffsetWidth&amp;ClientWidth&amp;ScrollWidth
參考連結
  • 《深入了解CSS盒模型》 https://www.cnblogs.com/cheng...
  • 《怪異模式和嚴格模式》 http://blog.sina.com.cn/s/blo...
  • 《标準模式與怪異模式的共存緣由及其使用》 https://blog.csdn.net/liyuans...