Margin的深入了解
Margin的深入了解
关于margin对于一个前端开发者是非常常见的一个CSS属性,而我今天所分享margin属性是为了更加深入的了解margin的一些特性,从而在实际应用中,减少代码量。主要内容如下:
1.关于margin的百分比特性。
2.关于margin的auto的作用机制。
3.关于margin的重叠。
4.关于margin的负值。
一、margin的百分比特性。
我们使用百分比时经常会忽略这个问题,margin的百分比相对于我们直接设置margin-top这类有所不同,margin的百分比是相对于容器水平宽度来计算的。这里有两种情况:
1.作用元素为普通元素(float\position等均不是普通block元素)
在这种情况下,百分比是相对于父元素的宽度计算。如:
<div style="width: 300px; height: 100px;">
<div style="width: 100px; height: 40px; margin: 10%;display: inline-block;"></div>
</div>
(注意:为什么这里我要用inline-block呢。)
此时margin值为父元素宽度的10%,也就是margin-top为30px,margin-left为30px。
2.作用元素为绝对定位元素
在这种情况下,百分比是相对于祖先元素或者最近的定位父元素宽度计算的。如:
<div style="width: 800px; height: 150px; ">
<div style="width: 300px; height: 100px; margin-left: 100px; ">
<div style="width: 100px; height: 40px; margin: 10%; position: absolute;"></div>
</div></div>
此时因为div使用了position,所以margin值是根据祖先元素的宽度进行计算。
二、margin的auto的作用机制。
关于margin的auto可能大家在熟悉不过了,用的最多的可能就是margin:0 auto;来进行水平居中定位了,但是你真的了解它是怎么实现的吗?是否你也遇到过img图片无法使用这个水平居中和margin:auto 0 无法进行垂直居中呢?接下来带着疑问,我将分享我理解的auto机制。
我用比较通俗的方式表达margin:auto的机制,便是为了填充因为强制变更尺寸而设计的属性。
举一个例子:
第一个例子是在一个div中,加入了一个没有设定宽度的p标签,众所周知p标签是一个块级元素,而浏览器默认为水平流布局,所以p标签水平独占一行,然后我们对比第二个例子,是设定了强制设定宽度100px的p标签但依旧独占一行,然后对比第三个例子,是强制设定了宽度100px并且margin-right:100px,margin-left:auto的p标签。此时margin-left:auto既是左边剩余空间大小。这样我们就很好理解为什么margin:0 auto能使元素水平居中了。是因为它相当于margin-left:auto;margin-right:auto;即直接把剩余空间平分给两侧处理。可能大家都经常使用第三个列子中没有添加auto时,margin-right始终不能执行,现在可以知道它的原理了吧。下次就可以使用它了。
理解了上面的机制后,我们看看为什么img使用上面的方法依旧不行呢。现在应该很多朋友都知道了,因为img是inline水平,及时你使用margin:0 auto;但是它没有需要处理的剩余空间,所以依旧无法实现居中,这个时候我们只要让它变成block元素,效果就自然呈现了。
解决了第一个问题,现在我们解决第二个问题,我们是否能用margin:auto 0来实现垂直居中呢?答案是:当然可以得!
在前面我们讲到浏览器是默认为水平流布局,及块级元素是会自动填充满一整行的。而我们的auto是处理被更改的剩余空间的,而我们的高度方向并不是自动充满一整行,所以即使你强制设定了高度,但是依旧没有的剩余空间,没有剩余空间auto自然不会做出反应。可能小伙伴们已经知道如何解决这一个问题了,既是把水平流布局更改为垂直流布局。改变布局后,垂直方向即可自动填充一列,writing-mode:vertical-lr;是css3中的属性,即改变此元素的布局为垂直流布局。这样,一个垂直居中及完成了。
有小伙伴要问了,现在垂直居中了,但是水平又不能居中了。现在即刻分享水平垂直方向都居中的办法(办法有很多,此处是根据margin和绝对定位来实现的)。
代码先行:
<div style="width: 500px; height: 300px; position: relative;">
<div style=" width: 100px; margin: auto; height: 100px; position: absolute; top: 0; right: 0; left: 0; bottom: 0" ></div>
</div>
细化分析,我们给img元素一个绝对定位,然后给它top/left/bottom/right都设置为0,此时里面div元素填充满整个外层div,然后我们强制改变了他的宽度很高度,此时它便有了剩余空间,根据上面的机制,auto处理了剩余空间,及让它水平垂直都成功居中。
三、margin的重叠概念
关于margin的重叠我们在实战中经常会出现,下面举例一个简单的例子:
*{ margin: 0; padding: 0; }
p{line-height: 1em; margin: 1em 0;}
<p style="">1</p>
<p style="">2</p>
这种例子在实际中很常出现,但到底有什么端倪呢。当你在浏览器上显示出这段代码的时候,你会发现,在我们常理判断下,俩个p标签都有margin,应该之间的距离有两个p标签的高度啊,但我们能从肉眼发现,完全没有。这就是margin的重叠机制。
但是这是有前提条件的:
1.必须为block水平元素(不包括float和absolute元素);
2.不考虑writing-mode,只发生在垂直方向;
margin重叠通常出现在三种情形下
第一种:既是上面举例的相邻两个兄弟元素
第二种:父元素和第一个或者最后一个子元素
第三种:空的block元素;
第一种我们已经举例说明,现在说第二种,父元素和第一个子元素的重叠。我们还是先写出代码块:
<div style="width: 200px; height: 200px; ">
<div style="margin-top: 100px;">1</div>
</div>
这也是我们经常遇见的问题,我们想要的结果是子元素与父元素的距离为100px,但是我们设置后发现,是父元素和浏览器出现了top值,这便是margin重叠的神奇,这就等同于父元素设置了top值,但有时候我们会觉得这样达不到想要的效果,其实,我们只需要在父元素加入overflow: hidden; 便可以清除重叠机制;父子元素重叠依旧有很多条件,下面我把列举出来,大家可以试试。
margin-top重叠条件:
1.父元素费块状格式化上下文元素
2.父元素没有border-top和padding-top值
3.父元素和第一子元素没有inline元素分隔
margin-bottom重叠条件:
1.父元素费块状格式化上下文元素
2.父元素没有border-bottom和padding-bottom值
3.父元素和最后一个元素没有inline元素分隔
4.父元素没有height相关的限制;
其实这些条件也是我们消除父子元素重叠的方式。
第三种空的block元素,下面是例子:
<div style=" overflow: hidden;">
<div style="margin: 1em 0;"></div>
</div>
里面的div设置了margin-top:1em,margin-bottom:1em,按照常理,外面容器应该被撑大到2em,但是实际上却依旧是1em;以上便是margin重叠的三种情况。它是一把双刃剑,所以我们需要合理利用它的重叠。
四、margin的负值
利用margin的负值在我们实战中是非常有效的一个技能。我们通常会遇到这么一个布局,三个或者多个div在同一行的显示的时候需要我们做出这样的效果(这样的效果有很多方法做到,这里只讨论margin实现):
在我刚入门的时候,我总是统一个div一个共有的margin值,得到如下效果:
然后再利用JS或者固定class属性来控制每一行最后一个div的margin值为0。不知道是否有朋友和我一样这样做,这确实不算一个有用的办法。而margin负值改变了这一切,让我们并不需要去单独处理某一div。
.box{width: 320px; height: 200px; overflow: hidden;}
.box>div>div{width: 100px; height: 100px; background-color: royalblue; float: left;margin-right: 10px;}
.box>div{margin-right: -10px;}
<div class="box">
<div>
<div>1</div>
<div>2</div>
<div>3</div>
</div>
</div>
根据上面的代码,我们轻易的达到了我们想要的效果,现在我们再分析,这是如何做到的。在分析之前,我们要了解margin有一个很实用的技能,便是改变可视尺寸(前提条件:无高宽的普通block元素和只针对水平方向)。这个技能便是我们实现这个效果的重点。简单的说,在没有设置宽高的时候,我们div元素的宽度是外层容器的宽度,当我们给div一个margin-left:100px时,div元素相距左边有100px,而我们div元素的宽度就变成了外层容器宽度减去100px;同理,当我们给div设置了margin-right:-10px的时候,相当于容器就在原来的基础上向右边多出来10个像素,而这10个像素正好是我们margin需要的空间,自然我们要排列的div就不会跑到下一行里去了,而在最外层设置overflow:hidden;是为了也不影响我们外面的所有布局。可能只从文字上还是比较难以理解,所以代码还需要自己实际操作才能让它深入你心。
关于margin负值可不只是这么一点用处,下面我们将分析一个关于margin-bottom负值所带来的经典案例:等高布局。
我们通常希望,不管左边内容和右边内容是否一致,但是他们最终外面的容器高度都希望一直。很多小伙伴一般情况是使用固定高度来解决这么一个问题,但是有时候我们并不知道我们其中的内容到底是多少毕竟大多数时候都是后台来生成这个内容的,那固定高度的办法固然就失败了。这时候,就该我们margin-bottom出击了。
<style>
*{ margin: 0; padding: 0; list-style: none;}
.red,.green{float: left; width: 300px; margin-bottom: -600px; padding-bottom: 600px;}
.red{}
.green{background-color: green;}
.content{ overflow: hidden;}
</style>
<body>
<div class="content">
<div class="red">
<ul>
<li>1</li>
</ul>
</div>
<div class="green">
<ul>
<li>1</li>
<li>2</li>
<li>2</li>
</ul>
</div>
</div>
效果如下:
不论你两边内容是否一致,已经等高,首先我们给我们内容div给出一个足够大的margin-bottom负值,然后再使用padding撑开这个div,此时这个div大小足以让我们放入足够多的列表。(注:在我理解看来,其实也是设置一个高度,只是这个高度并不像直接设置出来的高度那样直接显示出来暂具空间,而是根据内容慢慢显示出来,overflow:hidden就是拿来隐藏没有使用的空间高度)。
不知道你读完后是否觉得我们常用的margin也这么神奇呢?又或许其实上面的效果你可以用很多方法来代替它,这或许不是最优解,但是多一种方法会让我们多一种思路。如若有错的地方,希望大家指出。