深入了解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文檔開頭聲明)用以告訴其他人這個文檔的類型風格
- 産生于标準化浪潮以前的網頁并沒有DOCTYPE聲明。是以'沒有DOCTYPE'意味着觸發怪異模式:既依據舊式的CSS規則渲染網頁。
- 相反,如果開發者明确知道包含DOCTYPE,他們應該明白他們想要怎麼做。是以大部分的DOCTYPE聲明将觸發嚴格模式:即依據标準的CSS規則渲染網頁。
- 任何新的或未知的DOCTYPE将觸發嚴格模式。
- 一些頁面依據怪異模式而寫,但是卻包含DOCTYPE。這種情況下各個浏覽器依據自己的DOCTYPE規則清單來觸發怪異模式。
所有IE的觸發 —— 在DTD聲明前加上HTML注釋
<!--Let IE into quirks mode--> 隻要在DTD聲明前加注釋或者任何标簽即可
<!DOCTYPE html>xml
對于以上兩種不同的網頁模式,産生了兩種不同的盒模型,一個是
标準模型
,一個是
IE模型
。
标準模型的寬高 = 内容(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
5.DOM屬性之 OffsetWidth / ClientWidth / ScrollWidth
6.邊距重疊
什麼是邊距重疊
如下圖,父元素沒有設定margin-top,而子元素設定了margin-top:20px;可以看出,父元素也一起有了邊距。
<!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
- 根元素
應用場景
- 自适應兩欄布局
- 清除内部浮動
- 防止垂直margin重疊
看一個垂直margin重疊例子
<div class="container">
<div class="backgroundDom">
<div class="top"> Top margin-bottom: 30px</div>
<div class="bottom"> 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;
}
複制
效果圖
用BFC可以解決垂直margin重疊的問題
方法一 采用float或者position設定為absolute/fixed 脫離文檔流
float: left;
position: absolute;// 或者fixed
複制
方法二 設定display為inline-block,table-cell,table-caption,flex,inine-flex
display: inline-block;
複制
方法三 添加一個父元素包裹,并設定overflow為scroll/hidden/overlay/auto
<div class="container">
<div class="backgroundDom">
<div class="top"> Top margin-bottom: 30px</div>
<div style="overflow: hidden">
<div class="bottom"> Bottom margin-top: 50px</div>
</div>
</div>
</div>
複制
參考連結
- 《深入了解CSS盒模型》 https://www.cnblogs.com/cheng...
- 《怪異模式和嚴格模式》 http://blog.sina.com.cn/s/blo...
- 《标準模式與怪異模式的共存緣由及其使用》 https://blog.csdn.net/liyuans...