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

深刻理解CSS盒模型、BFC、OffsetWidth&ClientWidth&ScrollWidth

本文將從盒模型開始,一步步涉及一些常見的前端筆試和麪試點
主要參考自第一篇文章,然而筆者在讀的時候未覺詳盡,便又去網上查閱了一番,擴充了其內容,但願也能給同窗們提供一些參考。

下面本文章將會從如下幾個方面談談盒模型。css

  • 基本概念:標準模式和怪異模式,標準模型和IE模型
  • CSS如何設置這兩種模型
  • JS如何設置獲取盒模型對應的寬和高
  • 實例題(根據盒模型解釋邊距重疊)
  • BFC(邊距重疊解決方案)

1.盒模型是什麼

2018搜狐前端筆試題
盒模型本質上是用以封裝HTML元素的概念盒子,它包含了邊距,邊框,填充以及實際內容。
即由外向裏是 margin, border, padding, contenthtml

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則只提供了怪異模式。dom

選擇使用哪一種模式須要一個觸發器,而 「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>xmlflex

對於以上兩種不一樣的網頁模式,產生了兩種不一樣的盒模型,一個是標準模型,一個是IE模型網站

clipboard.png

clipboard.png

標準模型的寬高 = 內容(content)的寬高,ui

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
clipboard.png

5.DOM屬性之 OffsetWidth / ClientWidth / ScrollWidth

  1. OffsetWidth 對象所在元素的實際寬度

    dom.offsetWidth = dom_content + padding + border(包含滾動條)+ margin
  2. ClientWidth 對象內容的可視區域的寬度

    dom.clientWidth = dom_content + padding(不包含滾動條)
  3. ScrollWidth 對象的實際內容的寬度(包含滾動區域中未顯示徹底的部分)

    dom.scrollWidth = real_content + padding

6.邊距重疊

什麼是邊距重疊

以下圖,父元素沒有設置margin-top,而子元素設置了margin-top:20px;能夠看出,父元素也一塊兒有了邊距。

clipboard.png

<!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;
}

效果圖

clipboard.png

用BFC能夠解決垂直margin重疊的問題

方法一 採用float或者position設置爲absolute/fixed 脫離文檔流

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

方法二 設置display爲inline-block,table-cell,table-caption,flex,inine-flex

display: inline-block;

clipboard.png

方法三 添加一個父元素包裹,並設置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>

clipboard.png

參考連接

相關文章
相關標籤/搜索