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种不同的方法。
本文版权归本人和饥人谷所有,转载请注明来源。