1.在什么場景下會出現外邊距合并?如何合并?如何不讓相鄰元素外邊距合并?給個父子外邊距合并的范例
概念:在CSS當中,相鄰的兩個盒子(可能是兄弟關系也可能是祖先關系)的外邊距可以形成成一個單獨的外邊距。這種合并外邊距的方式被稱為合并,并且因此所結合成的外邊距稱為合并外邊距。
合并的結果:
兩個相鄰的外邊距都是正數時,合并的結果是它們兩者之間較大的值。
兩個相鄰的外邊距都是負數時,合并的結果是兩者絕對值的較大者。
兩個外邊距一正一負時,合并結果是兩者的相加的和。
產生合并的必備條件:margin必須是鄰接的!
而根據w3c規范,兩個margin是鄰接的必須滿足一下條件:必須是處于常規文檔流(非float和絕對定位)的塊級盒子,并且處于同一個BFC當中。
沒有線盒,沒有間隙(clearance,下面會講到),沒有padding和border將他們分割開。
-
都屬于垂直方向上相鄰的外邊距,可以是下面任意一種情況。
- 元素的margin-top與其第一個常規文檔流的子元素的margin-top
- 元素的margin-bottom與其下一個常規文檔流的兄弟元素的margin-top。
- height為auto的元素的margin-bottom與其最后一個常規文檔流的子元素的margin-bottom
- 高度為0并且最小高度也為0,不包含常規文檔流的子元素,并且自身沒有建立新的BFC的元素的margin-top和margin-bottom。
那么根據上面的文檔規范產生外邊距合并的場景就是下面這幾種:
兄弟元素
父元素與第一個/最后一個子元素
空塊元素
以上情形混合
舉例說明:
- 兄弟元素外邊距合并
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title></title>
<style type="text/css">
*{
margin: 0;
padding: 0;
}
.box1{
width: 100px;
height: 100px;
border: 1px solid red;
margin: 30px;
}
.box2{
width: 100px;
height: 100px;
border: 1px solid blue;
margin: 50px;
}
</style>
</head>
<body>
<div class="ct">
<div class="box1"></div>
<div class="box2"></div>
</div>
</body>
</html>
上圖可以看到,相鄰的兄弟元box1與box2發生了外邊距合并,合并值為它們中較大的50px。
- 父元素與子元素:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title></title>
<style type="text/css">
*{
margin: 0;
padding: 0;
}
.ct{
background-color: #ccc;
width: 400px;
height: 400px;
margin: 100px;
}
.box1{
width: 100px;
height: 100px;
border: 1px solid red;
margin: 30px;
}
.box2{
width: 100px;
height: 100px;
border: 1px solid blue;
margin: 50px;
}
</style>
</head>
<body>
<div class="ct">
<div class="box1"></div>
<div class="box2"></div>
</div>
</body>
</html>
上圖可以看到,父元素ct的margin-top與第一個子元素box1的margin-top發生了合并,但是最后一個子元素box2的margin-bottom與父元素的margin-bottom卻沒有合并,原因是我們對父元素設置了height。
那么取消父元素的height試試看:
.ct{
background-color: #ccc;
width: 400px;
margin: 100px;
}
看上圖,取消height值(即height值為auto)之后父元素ct的margin-bottom與最后一個子元素box2的margin-bottom發生了合并。
- 空塊元素
<!DOCTYPE html>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title></title>
<style type="text/css">
.ct{
background-color: #ccc;
border: 1px solid;
}
.box1{
width: 100px;
height: 100px;
border: 1px solid red;
margin: 30px;
}
.box2{
height: 0px;
min-height: 0px;
margin: 50px;
}
</style>
</head>
<body>
<div class="ct">
<div class="box1"></div>
<div class="box2"></div>
</div>
</body>
</html>
上圖可以看到,box3為空塊元素,給它設置margin,它自身的margin-top與margin-bottom發生了合并,為50px。
- 以上幾種情形混合
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title></title>
<style type="text/css">
.ct{
background-color: #ccc;
width: 400px;
min-height: 0px;
margin: 100px;
}
.box1{
width: 100px;
height: 100px;
border: 1px solid red;
margin: 30px;
}
.box2{
width: 100px;
height: 100px;
border: 1px solid blue;
margin: 50px;
}
.ct1{
height: 0px;
min-height: 0px;
margin: 100px;
}
.ct2{
width: 100px;
height: 100px;
border: 1px solid red;
}
</style>
</head>
<body>
<div class="ct">
<div class="box1"></div>
<div class="box2"></div>
</div>
<div class="ct1"></div>
<div class="ct2"></div>
</body>
</html>
上圖可以看到,盒子ct與盒子ct2之間的外間距為100px,期間發生了多次外邊距合并。
對合并結果的值舉例:
- margin值都是正數:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title></title>
<style type="text/css">
*{
margin: 0;
padding: 0;
}
.ct{
background: pink;
}
.box1{
width: 100px;
height: 100px;
border: 1px solid red;
margin: 30px;
}
.box2{
width: 100px;
height: 100px;
border: 1px solid blue;
margin: 50px;
}
</style>
</head>
<body>
<div class="ct">
<div class="box1"></div>
<div class="box2"></div>
</div>
</body>
</html>
從上圖看到,box1和box2相鄰,發生了邊距合并,合并值為它們中margin值更大的50px。
1.2;margin都為負數:
.ct{
background: pink;
border:1px soli green;
margin: 100px;
}
.box1{
width: 100px;
height: 100px;
border: 1px solid red;
margin: -30px;
}
.box2{
width: 100px;
height: 100px;
border: 1px solid blue;
margin: -50px;
}
為了更方便觀察給父元素設置margin:100px,從上圖可以看出,當2個兄弟元素的margin都為負數時,它們發生外邊距合并時,合并的值為絕對值更大的那一方,即為-50px。
1.3;margin值為一正一負
.ct{
background: pink;
border:1px soli green;
margin: 100px;
}
.box1{
width: 100px;
height: 100px;
border: 1px solid red;
margin: -30px;
}
.box2{
width: 100px;
height: 100px;
border: 1px solid blue;
margin: 50px;
}
從上圖可以看到,當margin值為一正一負時,它們發生的外邊距合并值為2者之和,即
-30px+50px=20px
。
如何阻止合并
- 創建了新的BFC的元素(例如浮動元素或者“overflow”值為“visible”以為的元素)與它的子元素的外邊距不會合并。
demo:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title></title>
<style type="text/css">
.ct{
background-color: #ccc;
width: 400px;
min-height: 0px;
margin: 100px;
overflow: auto;
}
.box1{
width: 100px;
height: 100px;
border: 1px solid red;
margin: 30px;
}
</style>
</head>
<body>
<div class="ct">
<div class="box1"></div>
</div>
</body>
</html>
BFC內部的子元素不會影響到外面的元素,反之也如此,所以阻止了合并。
- 浮動元素不與任何元素的外邊距產生合并(包括父元素和子元素)
demo:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title></title>
<style type="text/css">
.ct{
background-color: #ccc;
width: 300px;
height: 300px;
margin: 100px;
}
.box1{
width: 100px;
height: 100px;
background: red;
margin: 30px;
float: left;
}
.box1:after{
content: "";
display: block;
clear: both;
}
.box2{
width: 50px;
height: 50px;
background: blue;
margin: 15px;
}
</style>
</head>
<body>
<div class="ct">
<div class="box1">
<div class="box2"></div>
</div>
</div>
</body>
</html>
浮動元素會脫離文檔流,其他元素也就“感覺”不到它的外邊距了,自然就不會合并。
- 絕對定位元素不與任何元素的外邊距產生合并
demo:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title></title>
<style type="text/css">
.ct{
background-color: #ccc;
width: 300px;
height: 300px;
margin: 100px;
position: relative;
}
.box1{
width: 100px;
height: 100px;
background: red;
margin: 30px;
position: absolute;
}
</style>
</head>
<body>
<div class="ct">
<div class="box1"></div>
</div>
</body>
</html>
同浮動元素一樣,絕對定位會使元素脫離文檔流。
- inline-block元素不與任何元素的外邊距產生折疊。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title></title>
<style type="text/css">
.ct{
background-color: #ccc;
width: 400px;
height: 400px;
margin: 100px;
}
.box1{
width: 100px;
height: 100px;
background: red;
margin: 30px;
display: inline-block;
}
.box2{
width: 100px;
height: 100px;
background: blue;
margin: 50px;
}
</style>
</head>
<body>
<div class="ct">
<div class="box1"></div>
<div class="box2"></div>
</div>
</body>
</html>
文檔中規定,外邊距合并的塊級盒子的display屬性必須是下面三種之一:"block","list-item","table",所以,inline-block不符合要求。
- 一個常規文檔流元素的margin-bottom與它下一個常規文檔流的兄弟元素的margin-top會產生合并,除非它們之間存在間隙(clearance)
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title></title>
<style type="text/css">
.ct{
background-color: #ccc;
width: 400px;
height: 600px;
margin: 100px;
}
.box1{
width: 100px;
height: 100px;
background: red;
margin: 30px;
}
.box2{
float: left;
width: 100px;
height: 100px;
background: blue;
}
.box3{
clear:both;
width: 100px;
height: 100px;
background: pink;
margin: 50px;
}
</style>
</head>
<body>
<div class="ct">
<div class="box1"></div>
<div class="box2"></div>
<div class="box3"></div>
</div>
</body>
</html>
從上圖我們可以看出閉合浮動的元素的border-top會緊貼著相應的浮動元素的margin-bottom
- 一個常規文檔流元素的margin-top與其第一個常規文檔流的子元素的margin-top產生合并,條件為父元素不包含padding和border,子元素不包含clearance。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title></title>
<style type="text/css">
.ct{
background-color: #ccc;
border: 10px solid black;
padding: 10px;
width: 400px;
height: 400px;
margin: 100px;
}
.box1{
width: 100px;
height: 100px;
background: red;
margin: 30px;
}
</style>
</head>
<body>
<div class="ct">
<div class="box1"></div>
</div>
</body>
</html>
根據盒模型,padding和border會組織父元素與其第一個子元素的外邊距相遇。
- 一個 'height' 為 'auto' 并且 'min-height' 為 '0'的常規文檔流元素的 margin-bottom 會與其最后一個常規文檔流子元素的 margin-bottom 合并,條件為父元素不包含 padding 和 border ,子元素的 margin-bottom 不與包含 clearance 的 margin-top 合并。
同上。
- 一個不包含border-top、border-bottom、padding-top、padding-bottom的常規文檔流元素,并且其 'height' 為 0 或 'auto', 'min-height' 為 '0',其里面也不包含行盒(line box),其自身的 margin-top 和 margin-bottom 會合并。
反過來說只要不滿足上面任意一個條件,或者有一定內容,就不會發生自身合并。
- 關于clearance
根據w3c的文檔規定,閉合浮動的元素會在其margin-top以上產生一定的空隙(clearance),該空隙會阻止元素margin-top的合并,并作為間距存在于元素的margin-top的上方。
demo:
<div class="wrapper overHid">
<div class="big-box" style="box-shadow:0 20px 0 rgba(0,0,255,0.2);">non-float</div>
<div class="middle-box green floatL" style="opacity:0.6">float left</div>
<div class="middle-box red clear" style="margin-top:40px;box-shadow:0 -40px 0 rgba(255,0,0,0.2);">clear</div>
</div>
上面的圖中我們可以看到,我們為紅色塊盒設置的40px的margin-top(這里我們通過相同高度的陰影來將其可視化)好像并沒有對紫色塊盒起作用,而且無論我們怎么修改這個margin-top值都不會影響紅色塊盒的位置(當margin-top的值超過了clearance時,還是會影響的),而只由綠色塊盒的margin-bottom所決定。
通過w3c的官方規范可知,閉合浮動的塊盒在margin-top上所產生的間距(clearance)的值與該塊盒的margin-top之和應該足夠讓該塊盒垂直的跨越浮動元素的margin-bottom,使閉合浮動的塊盒的border-top恰好與浮動元素的塊盒的margin-bottom相鄰接。
也就是說可以得出這樣一個式子:r-margin-top + r-clearance = g-margin-top + g-height + g-margin-bottom。
2.去除inline-block內縫隙有哪幾種常見的方法?
在寫HTML代碼時如果有多個元素標簽使用換行,那么在元素設置display:inline-block后就會出現縫隙,就像這樣:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title></title>
<style type="text/css">
*{
margin: 0;
padding: 0;
}
li{
list-style-type: none;
}
.box{
border: 1px solid red;
margin-left: 10px;
}
li{
display: inline-block;
background: blue;
color:#fff;
padding: 3px;
}
</style>
</head>
<body>
<ul class="box">
<li>tag1</li>
<li>tag2</li>
<li>tag3</li>
</ul>
</body>
</html>
有以下方法可以消除:
- 使結束標簽沒有換行或空格
這樣:
<body>
<ul class="box">
<li>tag1</li><li>tag2</li><li>tag3</li>
</ul>
</body>
或者是這樣:
<body>
<ul class="box">
<li>tag1</li
><li>tag2</li
><li>tag3</li>
</ul>
</body>
- 使用margin負值
li{
display: inline-block;
background: blue;
color:#fff;
padding: 3px;
margin-left: -4px;
}
.box>li:first-child{
margin-left: 0;
}
使用margin負值時要注意,第一個子元素會跑到父元素外面,所以要單獨對第一個子元素進行修正。
這個方法有另外一個問題就是各個瀏覽器需要使用的margin負值不一樣,在默認字體下,chrome瀏覽器是-4px,就像上圖,而Firefox需要-5px才能消除,看下圖對比:
所以使用負margin除了要修正第一個子元素外,還需要考慮到瀏覽器兼容的問題。
- 使用浮動
.box{
border: 1px solid red;
margin-left: 10px;
overflow: hidden;
}
li{
display: inline-block;
background: blue;
color:#fff;
padding: 3px;
float: left;
}
浮動會使元素脫離文檔流,那么這些空格自然也影響不到這些浮動元素了。
那么理論上說使用絕對定位也能脫離文檔流,清除這些縫隙,但是需要計算每個元素的位置,太過于麻煩。
- 使用font-size為0
.box{
border: 1px solid red;
margin-left: 10px;
font-size: 0;
}
li{
display: inline-block;
background: blue;
color:#fff;
padding: 3px;
font-size: 16px;
}
空格其實也是一種字符(也能被選定),那么font-size也能對空格進行控制,所以只要在父元素中使用font-size:0,然后在子元素設置你需要的字體大小,就能清除這些縫隙了。
3.父容器使用overflow: auto| hidden撐開高度的原理是什么?
對父元素使用overflow: auto| hidden,會使這個父元素形成一個新的BFC,這個BFC里面的子元素不會受到外界元素的影響,也不回影響外界的元素。
BFC有一個特性就是可以包含浮動元素,也就是說在計算BFC的高度時,浮動元素也參與計算,所以父容器的高度被撐開。
4.BFC是什么?如何形成BFC,有什么作用?
-BFC是什么
BFC(Block Formatting Context),直譯為“塊級格式化上下文”。BFC是一個獨立渲染的區域,里面元素的布局是不受外界的影響(我們往往利用這個特性來消除浮動元素對其非浮動的兄弟元素和其子元素帶來的影響。)并且在一個BFC中,塊盒和行盒(行盒由一行中所有的內聯元素所組成)都會垂直的沿著其父元素的邊框排列。
- 如何形成
- float值為left或right
- position值為absolute或fixed
- display值為inline-block、table-cells、table-captions、或inline-flex
- overflow值不為visible
- 有什么用
- 可以包含浮動元素
- 不被浮動元素覆蓋(清除浮動)
- 阻止外邊距合并
- 利用BFC的獨立性來設計布局
5.浮動導致的父容器高度塌陷指什么?為什么會產生?有幾種解決方法?
浮動的子元素會脫離文檔流,那么父容器在計算高度時會忽略這個浮動的子元素,導致高度坍塌。
就像這樣:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
<style type="text/css">
div {
border: 1px solid black;
padding: 5px;
}
img {
border: 1px solid red;
float: left;
}
</style>
</head>
<body>
<div>
<img src="img/blue.jpg" />
<img src="img/green.jpg" />
<img src="img/lightblue.jpg" />
</div>
</body>
</html>
那么解決方法如下:
1.使父元素形成BFC:
div {
border: 1px solid black;
padding: 5px;
float: left;
}
如圖,根據問答3的回答,使用float,讓父元素形成BFC,能夠包含浮動的子元素。
注意,使用這些屬性形成BFC的時候會對父元素或者子元素造成一些影響,需要根據實際情況來選擇合適的屬性。
2.在浮動的子元素后面增加一個div來清除浮動
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
<style type="text/css">
div {
border: 1px solid black;
padding: 5px;
}
img {
border: 1px solid red;
float: left;
}
#clear{
display: none;
clear: both;
}
</style>
</head>
<body>
<div>
<img src="img/blue.jpg" />
<img src="img/green.jpg" />
<img src="img/lightblue.jpg" />
<div id="clear">
</div>
</div>
</body>
</html>
額外增加一個div,影響語義化。
3.使用偽元素來建立一個空塊清除浮動。
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
<style type="text/css">
div {
border: 1px solid black;
padding: 5px;
}
img {
border: 1px solid red;
float: left;
}
.clearfix:after {
content: '';
display: block;
clear: both;
}
.clearfix {
*zoom: 1;
}
</style>
</head>
<body>
<div class="clearfix">
<img src="img/blue.jpg" />
<img src="img/green.jpg" />
<img src="img/lightblue.jpg" />
</div>
</body>
</html>
目前最適用的方法,不會造成額外的影響。
6..以下代碼每一行的作用是什么? 為什么會產生作用? 和BFC撐開空間有什么區別?
.clearfix:after {
content: '';
display: block;
clear: both;
}
.clearfix {
*zoom: 1;
}
- .clearfix:after
使用after偽類在所有包含.clearfix類的元素里面創建一個虛擬子元素,該子元素為父元素的最后一個子元素。
關于偽元素的使用可以參考這篇文章學習使用:before和:after偽元素,官方的文檔是用“前”、“后”
來描述偽元素的位置,所以我曾經以為偽元素是創建一個兄弟元素,但是審查元素時又發現偽元素是創建目標元素的子元素,所以查了一下資料,通過大漠這篇的博客就確定了偽元素確實是創建一個子元素。
content: ''
這個偽元素的內容為空display: block;
默認的偽元素是行內元素,但是下面的clear屬性只對塊元素起作用,所以用display將這個偽元素改為塊元素。clear:both
清除偽元素兩邊的浮動元素。zoom: 1
ie8以下是不支持偽元素:after的,ie通常是觸發hasLayout來清除浮動了,常見的就是zoom:1,*
號是是IE68的一個bug,IE68看到以*
開頭的代碼,會忽略星號,執行后面的代碼。
這段代碼總的作用就是利用after偽類來創建一個虛擬空塊元素,再利用clear屬性清除浮動。
而BFC是撐開空間是利用了BFC可以包含浮動元素的特性,與清除浮動讓父容器撐開空間是2種不同的方法。
本文版權歸本人和饑人谷所有,轉載請注明來源。