盒尺寸中padding负责内边距,通常状况下(抛开上一章的诡异现象)不会给使用者带来太多的麻烦,所以做者称之为温和的padding,而margin则有些激进,虽然说负责外边距,但有时候还能作一些"内边距"的事情(负边距),还自带了些特殊属性(如叠压),本文会经过实例深刻探究margin负边距的使用以及叠压问题的产生和计算方式css
说到margin,一般咱们会想到一层透明的外边距,用于划分元素与元素之间的界限,然而margin除了能够划分边界,还能够改变元素"可视尺寸",注意这里我没有用内部尺寸,由于margin和padding在改变元素可视尺寸方面几乎是互补的。对于设定了width或者元素保持"包裹性"的时候,padding会改变元素的可视尺寸,而margin正好相反,margin只会在元素“充分利用空间”状态的时候,才能改变元素的可视尺寸 。固然这两个也不是彻底互补的,这里看成一个思考,请本身体会。 html
刚才说到了设定了宽度的元素和保持“包裹性”的元素不能经过margin影响可视尺寸,设定width这个很好理解,那么保持包裹性的元素有哪些呢? 浏览器
这里来列举一下常见的有:absolute,fixed,float ,inline-box(inline-block, table-cell, table-caption, flex, inline-flex)。 markdown
因此咱们在遇到上述元素的时候,就不须要尝试用margin去改变他的可视区了,无效。因为我平时最爱用的inline-block元素也在其中,因此我不多用margin负边距去管理元素可视区。下面,咱们来看一个最简单的margin负边距影响元素可视区的演示,代码以下: 编辑器
<div class="father">
<div class="son"></div>
</div>
<style> .father{ width: 300px; height: 200px; background: #F56C6C; } .son{ margin: 0 -20px; height: 100px; background: #E6A23C; } </style>
复制代码
因为markdown编辑器支持标签语言,所以咱们能够直接预览最终效果以下(小提示:你能够经过浏览器直接检查下面的元素看到CSS样式) 布局
这里有两个要注意的点,首先son是display默认为block的元素,符合充分利用水平空间的规则,其次son自身不带width申明,因此width在负边距的做用下最终width = father.width + 20*2 ,如上图所示。 测试
负边距除了可以改变"充分可利用空间"的可视区域以外,还能够利用其能够改变尺寸的特性,实现一些特殊的布局效果。如做者给出的例子以下: flex
<div class="box box-right-same">
<div class="full">
<p>DOM文档流中,图片定宽在右侧,视觉呈现也在右侧,顺便表现此时一致。</p>
</div>
<img src="1.jpg" class="img">
</div>
<style> /* 右浮动,图片DOM在后,和视觉表现一致 */ .box-right-same > .full { width: 100%; float: left; } .box-right-same > .full > p { margin-right: 140px; } .box-right-same > img { float: left; margin-left: -128px; } </style>
复制代码
结果以下图所示: spa
结果如上图,在本例中,因为full的宽度是100%,且他和img元素均为浮动元素,所以img元素在没有设置margin以前应当流到full元素下面,而加了负边距以后,img元素的宽度增长了128px,正好等于图片的宽度,此时图片元素所有跑到了增长的负边距中去,致使img元素自己变成了"0宽度",因而0宽度元素就浮上来了,由于他“不须要”占据宽度,他的宽度由负边距提供了。(这一段测试我的持保留意见,有不一样观点的可在下方留言) 3d
块级元素的上外边距(margin-top)和下外边距(margin-bottom)有时会发生“重叠”,这样的现象叫作margin合并。从定义上来看,能够确认两个信息。
(1)块级元素
(2)垂直方向。不考虑writing-mode的状况下,文档流默认为水平方向,所以这里的垂直方向是指垂直于文档流的方向,而不是简单的上下左右。
margin合并通常有三种场景
(1)相邻兄弟元素margin合并。
(2)父级和第一个/最后一个子元素。(做者的这个表达可能有一些问题,须要配合第三点来看)
(3)空块级元素的margin合并。
下面我将列举一些场景,来探究一下每一个场景的哪些margin发生了叠压。
<p>一段话</p>
<p>一段话</p>
<p>一段话</p>
<p>一段话</p>
<style> p{ margin: 1em 0; } </style>
复制代码
结果以下图所示:
这个例子中,显然是相邻兄弟元素的margin合并,能够看到p标签的上下外边距是1em,但每两行之间的的距离并非1+1=2,而是1和1叠压以后 = 1。下面来看第二个场景。
<div class="father">
<div class="son"></div>
</div>
<style> body{ margin: 0; } .father{ background: green; height: 400px; } .son{ margin-top: 200px; height: 200px; background: red; } </style>
复制代码
结果以下图所示:
在本例中,父元素高度400,子元素高度200,上外边距200,想象之中,子元素应该"定位"在父容器底部,但因为父级和第一个/最后一个子元素的margin叠压(这个理论是否彻底正确咱们在后面的例子中证实),子元素的margin-top"借"给了父元素,而后本身的margin-top彷佛变成了0,在实际开发的时候,父子元素的margin合并也会给咱们带来许多麻烦,那么,如何解决这个烦恼呢?做者提供了几种方案(知足任何一种便可),这里我会有一些本身的观点在里面。
(1)父元素设置为块状格式化上下文元素(听不懂不要紧,overflow:hidden就能够)
(2)父元素设置border-top/bottom(>0)的值(border-top解决margin-top,border-bottom解决margin-bottom)
(3)父元素设置padding-top/bottom(>0)的值(同border)
(4)父元素和第一个子元素之间添加(非空)内联元素进行分隔(针对margin-top)
(5)父元素和最后一个子元素之间添加(非空)内联元素进行分隔(针对margin-bottom)
(6)父元素设置height,min-height或max-height(注意本条只对margin-bottom有效)
通过本人测试,CSS世界彷佛对申明这个玩意不感冒,做者说设置border/padding的值便可,我设置0,"居然"不行,因此补充了>0的限制条件,但因为这条规则破坏了容器的大小,因此不推荐这两种解决方案。
在实际验证的时候,第四条/第五条在谷歌浏览器中也会因为“0”值不生效,所以我把它划掉了,由于这个解决方案实在是太蠢了,你必需要在内联元素里面写点什么才能解决margin叠压问题,这可比破坏容器大小严重多了,直接就影响文本显示了。所以最佳的解决方案就是第一条,父元素设置为块状格式化上下文元素,虽然我并不知道这个是什么意思。
进入今天的重头戏,我以为做者写的有问题的一个点,咱们先在刚才父子叠压代码的基础上添加一个空块级标签。
<div class="father">
<!-- 我是一个空块级元素 -->
<div></div>
<div class="son"></div>
</div>
<style> body{ margin: 0; } .father{ background: green; height: 400px; } .son{ margin-top: 200px; height: 200px; background: red; } </style>
复制代码
此时你会发现页面无任何变化,其实这里涉及到两个知识点,首先是空块级标签的margin叠压,因为其自己没有任何宽高,也没有margin值,所以他只会和相邻的son元素进行叠压,空div的margin-bottom:0 和 son元素的margin-top:200合并以后,能够认为空div的margin-bottom变成200了,此时,空块级元素的margin-bottom:200又和自身的margin-top:0合并,使得自身的margin-top也受到了感染,最后叠压成垂直margin=200的空块级元素,这时候父元素感应到他的第一个子元素有margin-top,就和他进行了一波margin-top叠压,因此最终的表现和第二个例子的结果相同。
测试到这里,我还以为没什么问题,而后我又想到刚才内联空标签对第二个例子也不会有任何影响,那么问题来了,父级和第一个/最后一个子元素的叠压这句话到底是什么意思?惊觉这句父元素和第一个子元素之间添加内联元素进行分隔彷佛还有什么别的意思,我我的猜想做者是想表达内联元素破坏了发生叠压的三个规则,由于内联元素不会发生margin叠压,所以能够用这个进行分割(即便该内联元素为空,固然实际测试中为空是没有任何效果的)。根据测试结果,我提出的一个大胆的假设:margin叠压,会直接忽略掉全部空标签(固然空标签不能有什么奇奇怪怪的样式)。这么一来,内联空标签的问题就解决了。固然这个假设还有待验证,去做者提供的论坛碰碰运气。
关于margin合并的计算规则,我我的倾向于彻底套用做者的三句精辟总结:
这里我只说明正负值相加的状况,虽然这东西其实并无什么软用,看下面的例子
.a{margin-bottom:50px}
.b{margin-top:-20px}
<div class="a"></div>
<div class="b"></div>
复制代码
此时a和b的间距=-20+50 = 30px
老是喜欢以深刻命名,其实就是一个🐶测试,根据浏览器的表现结果,来猜想原理,在理解margin:auto以前,先来看下面这个例子。
<div class="father">
<div class="son"></div>
</div>
<style> body{ margin: 0; } .father{ height: 400px; background: yellow; } .son{ width: 200px; margin-right: 100px; margin-left: auto; height: 200px; background: red; } </style>
复制代码
结果以下图所示:
能够从结果中得出以下结论:
(1)margin:auto是有用的,去掉margin-left:auto后,margin-right失效
(2)margin:auto属性管理的是容器的剩余空间
何为容器的剩余空间?最寻常的情景就是你在body里添加了一个宽度
那么问题又出现了,为何此时在垂直方向上没有垂直居中呢?缘由在于触发margin:auto计算有一个前提条件,就是width或height为auto时,元素是具备对应方向的自动填充属性的。从本例来看,当son的width为auto时,son的宽度为100%,也就是可计算的剩余空间为100%-width具体值,当son的height为auto时,很差意思,son的高度变0了,看都看不见了,你还要居中他干啥。同时height:auto也不符合自动填充特性。
利用margin:auto管理剩余空间的特性,咱们除了能够作到元素的水平居中,还能够实现元素的"右浮动"。只须要以下设置便可.
<div class="father">
<div class="son"></div>
</div>
<style> body{ margin: 0; } .father{ height: 400px; background: yellow; } .son{ width: 200px; margin-left: auto; height: 200px; background: red; } </style>
复制代码
这里咱们经过margin-left:auto管理剩余空间,元素就自动右对齐了。
除了水平居中和右对齐,margin:auto还能够实现水平垂直居中。刚才也说到了,要实现垂直居中,只须要让元素在垂直方向上也就是height:auto具备自动填充属性便可。那么什么状况下height:auto有自动填充属性呢?有一种状况就能够,绝对定位元素设置了top和bottom属性以后,元素垂直方向上就会自动填满父容器。以下所示
<div class="father">
<div class="son"></div>
</div>
<style> body{ margin: 0; } .father{ height: 400px; background: yellow; position: relative; } .son{ position: absolute; width: 200px; height: 200px; background: red; margin: auto; left: 0; top: 0; right: 0; bottom: 0; } </style>
复制代码
因为设置了right,left,top,bottom值,子元素在水平垂直方向上都有用自动填充属性,经过margin管理剩余空间,就实现了垂直和水平方向的填充。
margin部分的内容就写到这。
不忘初心,方得始终
喜欢博主的童鞋能够扫描二维码加博主好友~ 也能够扫中间二维码入驻博主的粉丝群(708637831)~固然你也能够扫描二维码打赏并直接包养帅气的博主一枚。