深入理解css中的margin属性

  之前我一直认为margin属性是一个非常简单的属性,但是最近做项目时遇到了一些问题,才发现margin属性还是有一些“坑”的,下面我会介绍margin的基本知识以及那些“坑”。这篇博文主要分为以下几个部分:

  

第一部分:margin--基础知识

  要介绍margin的基础知识,我们不可回避地要谈到css盒子模型(Box Model),一般而言,css盒子模型是用来设计和布局的。它本质上是一个盒子,包括:外边距(margin)、边框(border)、内边距(padding)以及最中间的内容(content)。下图即为盒子模型(这里只谈W3C规范的标准盒模型,而不谈IE5和IE6在怪异模式中使用的非标准的盒子模型):

   我们要介绍的margin在最外层,因为margin(外边距)一定是透明的,所以它可以用来使得不同的盒子之间留有一定的间隙从而达到布局美观等效果。从上面的盒子模型中我们可以看到,margin在四周均存在,我们可以使用margin-top、margin-right、margin-bottom、margin-left分别设置这四个方向的margin值。(注:由于这部分知识较为基础,所以我不再在这部分不做更多介绍)

 

第二部分:margin--在同级元素(非父子关系)之间应用

  这一部分主要介绍水平方向和竖直方向的外边距的合并问题。

 (1)水平方向的外边距合并

     两个水平方向的盒子相遇,那么最终两者之间的距离为左边盒子的右外边距和右边盒子的做外边距之和。

     例1:

       代码如下:

    

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>水平方向的两个盒子</title>
  6. <style>
  7. *{
  8. margin:0;
  9. padding:0;
  10. border:0;
  11. }
  12. body{
  13. font-size: 0;
  14. }
  15. .left{
  16. width: 100px;
  17. height: 100px;
  18. background: red;
  19. display: inline-block;
  20. margin-right: 50px;
  21. font-size: 20px;
  22. }
  23. .right{
  24. width: 100px;
  25. height: 100px;
  26. background: yellow;
  27. display: inline-block;
  28. margin-left: 50px;
  29. font-size: 20px;
  30. }
  31. </style>
  32. </head>
  33. <body>
  34. <div class="left">宽为100px,右边距为50px</div>
  35. <div class="right">宽为100px,左边距为50px</div>
  36. </body>
  37. </html>

  效果如下:

这时两者之间的距离刚好为100px。

  补充说明:大家可以看到,为了使得两个div(块状元素)脱离正常的文档流我使用了display:inline-block;属性,另外,我还把body的font-size设置为0,这样可以解决inline-block自身的问题(如果不清楚这里的描述可以看我的博文《理解与应用css中的display属性》,这篇文章介绍了inline-block存在的问题),否则两个div的举例会大于100px。当然使用float也可以使得两个div出现在同一行中。

  (2)竖直方向的外边距合并

  两个竖直方向的盒子相遇时,其竖直方向的距离等于上方盒子的下外边距和下方盒子的上外边距中较大的一个。

  例2:

  

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>水平方向的两个盒子</title>
  6. <style>
  7. *{
  8. margin:0;
  9. padding:0;
  10. border:0;
  11. }
  12. .top{
  13. width: 100px;
  14. height: 100px;
  15. margin-bottom: 100px;
  16. background: red;
  17. }
  18. .bottom{
  19. width: 100px;
  20. height: 100px;
  21. margin-top: 50px;
  22. background: green;
  23. }
  24. </style>
  25. </head>
  26. <body>
  27. <div class="top">高为100px,下边距为100px</div>
  28. <div class="bottom">高为100px,上边距为50px</div>
  29. </body>
  30. </html>

  效果如下:

这时我们肉眼都可以观察出来,两者竖直方向的举例大约为100px(实际就是100px)而非100+50=150px;这正是因为两个竖直方向的盒子相遇时,其竖直方向的距离等于上方盒子的下外边距和下方盒子的上外边距中较大的一个。

  

  另外一个有趣的例子就是:假设有一个元素同时设置了margin-top和margin-bottom,但是内容为空,那么这两个margin值也会叠加,值为两者最大的一个,它类似与竖直方向上两个盒子margin值的叠加。代码如下:

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>水平方向的两个盒子</title>
  6. <style>
  7. *{
  8. margin:0;
  9. padding:0;
  10. }
  11.  
  12. .top{
  13. width: 500px;
  14. height: 100px;
  15. background: red;
  16. }
  17. .middle{
  18. margin-top: 100px;
  19. margin-bottom:50px;
  20. }
  21. .footer{
  22. width: 500px;
  23. height: 100px;
  24. background: green;
  25. }
  26.  
  27. </style>
  28. </head>
  29. <body>
  30. <div class="top">上面的div,高100px</div>
  31. <div class="middle"></div>
  32. <div class="footer">下面的div,高100px</div>
  33. </body>
  34. </html>

  最终的效果如下:

  我们发现这时在上面的div和在下面的div之间的举例并不是100+50=150px,而是两者中的最大者,即100px。

  

  那么W3C为什么会设定这样的标准而不设定和水平方向一样的标准呢?即margin值的叠加,实际上这也是有一定的道理的。比如我们需要设计一个由若干个段落构成的一个页面。我们需要设置margin-top和margin-bottom使得第一段和页面的最上方有一段距离,使得最后一段和最下方有一段距离。下面是不叠加和叠加的效果图:

我们可以看到左边的页面没有重叠,那么两个段落之间的举例就是最上方的两倍间距了,而右边的页面发生了重叠,则所有的间距都是相等的。或许这就是这样设定标准的目的吧,谁知道呢?

第三部分:margin--在父元素和子元素之间应用(重点

    第二部分介绍了同级元素之间使用margin,而这一部分将要介绍最有意思的父元素和子元素之间margin的应用。这一部分,我们同样从两个方面来讨论。一方面是子元素设置水平方向上的margin值,另一方面是子元素设置竖直方向的margin值。

  (1)在子元素中设置水平方向的margin值

    我们可以设置margin-left来控制子元素的左边框和父元素的左边框之间的举例。

    例3:

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>margin</title>
  6. <style>
  7. *{padding:0; margin:0; border:0;}
  8. .father{
  9. width: 500px;
  10. height: 500px;
  11. background: red;
  12. }
  13. .son{
  14. width: 100px;
  15. height: 100px;
  16. background: green;
  17. margin-left: 100px;
  18. }
  19. </style>
  20. </head>
  21. <body>
  22. <div class="father">
  23. <div class="son">宽度为100px,margin-left为100px。</div>
  24. </div>
  25. </body>
  26. </html>

  我将子元素的margin-left设置为了100px;效果如下:

即子元素的左边框和父元素的左边框之间的距离为100px。与在同级元素之间设置margin不同,因为同级元素之间的margin不会考虑到padding,但是在父元素和子元素就不同了,那么如果父元素中如果有padding,效果会是什么样的呢?请看下面一个例子:

  

  例4:

  下面我们在上面例子的基础上给父元素添加padding值。

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>margin</title>
  6. <style>
  7. *{padding:0; margin:0; border:0;}
  8. .father{
  9. width: 500px;
  10. height: 500px;
  11. padding:100px;
  12. background: red;
  13. }
  14. .son{
  15. width: 100px;
  16. height: 100px;
  17. background: green;
  18. margin-left: 100px;
  19. }
  20. </style>
  21. </head>
  22. <body>
  23. <div class="father">
  24. <div class="son">宽度为100px,margin-left为100px。</div>
  25. </div>
  26. </body>
  27. </html>

  上面的代码给父元素添加了100px的padding值,效果如下:

我们可以看到子元素举例上方的距离为100px,因为子元素一定是在父元素的content的部分的,这点毫无疑问。

但是经过测量可以发现子元素的左边框距离父元素的左边框之间的距离为200px,因为其中还有100px的左padding值,前面的例子因为我没有设置padding值,所以没有观察出来,因此这就说明了在子元素中设置margin-left,其值实际上是子元素的左边框距离父元素左padding内侧的距离。

 例5:margin-right的使用和margin-left的使用是相似的,我在这里只举一个例子。

  这个例子在子元素中设置了margin-right值,如下所示:

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>margin</title>
  6. <style>
  7. *{padding:0; margin:0; border:0;}
  8. .father{
  9. width: 500px;
  10. height: 500px;
  11. padding:100px;
  12. background: red;
  13. }
  14. .son{
  15. float: right;
  16. width: 100px;
  17. height: 100px;
  18. background: green;
  19. margin-right: 100px;
  20. }
  21. </style>
  22. </head>
  23. <body>
  24. <div class="father">
  25. <div class="son">宽度为100px,margin-right为100px。</div>
  26. </div>
  27. </body>
  28. </html>

  这个例子与例4的区别仅在与子元素的位置不同。效果如下:

通过这个例子可以说明margin-right的值是子元素的右边框和父元素的右padding内侧的距离。只是前面的几个例子我没有使用padding,所以无法观察出来。

  (2)在子元素中设置竖直方向的margin值

    按照前面的经验,理论上来说,我们同样可以通过设置margin-top的值使得子元素的上边框和父元素的上padding的内侧留有一定的距离。那么我们就试试吧!

  例6:

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>margin</title>
  6. <style>
  7. *{padding:0; margin:0; border:0;}
  8. .father{
  9. width: 500px;
  10. height: 500px;
  11. background: red;
  12. }
  13. .son{
  14. width: 100px;
  15. height: 100px;
  16. background: green;
  17. margin-top: 100px;
  18. }
  19. </style>
  20. </head>
  21. <body>
  22. <div class="father">
  23. <div class="son">高度为100px,margin-top为100px。</div>
  24. </div>
  25. </body>
  26. </html>

  这个例子我设置了margin-top为100px,效果如下:

这并不是我们想要的效果啊,我们希望子元素的上部距离父元素的上部为100px,可是我们看到的却是父元素的上部距离浏览器页面的上部有100px的距离,这是为什么呢?哪里出现问题了呢?

  

  实际上这是因为当父元素没有设置padding值以及border值时,出现了一个bug--父元素的上方与子元素的上方完全重合在了一起,无法分开。所以才会导致上述这种父元素和子元素同时向下的情况。

  对于这种问题解决方法有下面几种:

  • 方法一:给父元素添加padding-top值
  • 方法二:给父元素添加border值
  • 方法三:给父元素添加属性overflow:hidden;
  • 方法四:给父元素或者子元素声明浮动float
  • 方法五:使父元素或子元素声明为绝对定位:position:absolute;
  • 方法六:给父元素添加属性 overflow:auto; positon:relative;(注:此方法为后续添加,感谢博友@小精灵Pawn提供此方法)

  方法一:基于例6,在父元素的css代码中添加padding-top:1px;效果如下:

方法的唯一缺点就是增加了1px的误差。

  

  方法二:基于例6,在父元素的css代码中添加border-top:1px solid transparent;效果如下:

同样达到了效果, 缺点同方法一。

  

  方法三:基于例6,在父元素的css代码中添加overflow:hidden;效果如下:

 

同样达到了效果,并且没有任何误差的存在。堪称perfect!!!!

  

  方法四:给父元素或者子元素声明float;基于例6,在子元素css代码添加float:left;或者在父元素css代码添加float:left;均达到效果,这里不再展示相同的图片。

    优点:没有像素的误差。   缺点:float有时是不必要的。

  方法五:给父元素或者子元素添加position:absolute;属性。 同样达到效果。

    优点:同方法四。  且只要我们不使用top和left也不会有任何影响,所以这也是一种不错的方法。

(说明:博友 @laden666666 指出,上述方法三、四、五实际上都是去除子元素margin穿透父容器的方法,可以归类为bfc法,本质相同。 在此表示感谢)

方法六:给父元素添加overflow:auto;和position:relative;同样达到效果。

      此方法亲测有效,是博友 @小精灵Pawn提供,在此表示感谢。

第四部分:margin值的单位为%时的几种情况

    之前我举例子时使用margin,它的值都是以px为单位的,这个理解起来没有问题。但是如果margin值是以%为单位呢?实际上这时候百分比(%)是相对于该元素的父元素(容器),对于同级元素和父子元素都是如此。(再次感谢 博友@小精灵Pawn 提供的建议!!基于此建议补充这部分内容) 但是在同级元素中使用竖直方向的margin时会出现意想不到的结果,下面举例说明。

  (1)同级元素在水平方向使用值为%的margin

  例7:

  1. <head>
  2. <meta charset="UTF-8">
  3. <title>margin</title>
  4. <style>
  5. *{
  6. margin:0;
  7. padding:0;
  8. }
  9. .first{
  10. float: left;
  11. width: 200px;
  12. height: 200px;
  13. background: green;
  14. }
  15. .second{
  16. float: left;
  17. width: 200px;
  18. height: 200px;
  19. background: red;
  20. margin-left: 20%;
  21. }
  22. </style>
  23. </head>
  24. <body>
  25. <div class="first">宽为200,无margin</div>
  26. <div class="second">宽为200,margin-left为20%;</div>
  27. </body>
  28. </html>

这个例子中,设置两个元素向左浮动,以便于观察两者水平方向的margin。其中左边div无margin,右边div的margin-left为20%,效果如下:

从效果图可以看出两个div之间的间距始终为父元素(这里右边div的父元素即为body,其宽度为浏览器宽度)的20%。

 

  

  (2)同级元素在竖直方向使用值为%的margin

   根据例7的启发,我们可以猜想,如果在竖直方向上使用margin,且值的单位为%,那么最终两者之间的距离将是父元素(上例中为body)的百分数。那么究竟是不是这样呢?看下面的例子。

例8

  1. <head>
  2. <meta charset="UTF-8">
  3. <title>margin</title>
  4. <style>
  5. *{
  6. margin:0;
  7. padding:0;
  8. }
  9. .first{
  10. width: 200px;
  11. height: 200px;
  12. background: green;
  13. }
  14. .second{
  15. width: 200px;
  16. height: 200px;
  17. background: red;
  18. margin-top: 10%;
  19. }
  20. </style>
  21. </head>
  22. <body>
  23. <div class="first">高为200,无margin</div>
  24. <div class="second">高为200,margin-top为20%;</div>
  25. </body>
  26. </html>

这里设置上面的div无margin,下面的div的margin-top为10。效果如下:

 

我们发现,当我在缩小浏览器的高度时,竖直方向上的间距并没有缩小!!! 而当我缩小浏览器的宽度时,竖直方向上的距离缩小了!!!

这就说明:统计元素之间在竖直方向上使用margin,当值的单位为%时,它是相对于父元素的宽度。

  那么这里为什么不是如我们所希望的那样相对于浏览器的高度呢?知乎上有大神是这样解释的(原文地址:https://www.zhihu.com/question/20983035?rf=27109182):

 

  (3)父子元素使用值为%的margin

    对于父子元素,如果在子元素中使用单位为%margin,那么这个margin值是相对于父元素的宽度和高度(注意:这时的确是相对于父元素的高度!)的。

        例9  

    代码如下:

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>Document</title>
  6. <style>
  7. *{
  8. margin:0;
  9. padding:0;
  10. }
  11. .father{
  12. width: 500px;
  13. height: 300px;
  14. background: red;
  15. overflow: hidden;
  16. }
  17. .son{
  18. width: 100px;
  19. height: 100px;
  20. background: green;
  21. margin-top: 20%;
  22. margin-left: 20%;
  23. }
  24. </style>
  25. </head>
  26. <body>
  27. <div class="father">
  28. <div class="son"></div>
  29. </div>
  30. </body>
  31. </html>

  在这个例子中,我设置了margin-left的值为20%,margin-top的值为20%,父元素的width为500px,父元素的height为300px。下面看看效果吧。

从上图可以看出子元素的margin-top值最终同样是相对与父元素的宽度而非高度。

  

总结:

   这篇博文只介绍了margin的其中一部分知识点,但如果大家读后能有些许收获是再好不过的了。由于本人总结仓促,知识不足,错误在所难免,希望大家如果发现不妥之初能提出意见,我将非常感激。 

   补:将文章发布之后,得到了很多建议和指导,给予了我很多帮助,也促使我不断的修改博文,在此表示感谢!

  1.  
  1. 人之所以能,是相信能。

注:如需转载,请注明出处 http://www.cnblogs.com/zhuzhenwei918/p/6124263.html。

深入理解css中的margin属性的更多相关文章

  1. 深入理解CSS中的margin

    1.css margin可以改变容器的尺寸 元素尺寸 可视尺寸--标准盒子模型中盒子的宽度是不包括margin值的,clientWidth 占据尺寸--包括margin的宽度 outWidth不在标准 ...

  2. 理解css中的position属性

    理解css中的position 两种类型的定位 static类型:只有一个值position: static.position默认值 relative类型:包括三个值,这三个值会相互影响,允许你以特定 ...

  3. 解说css中的margin属性缩写方式

    <html> <body> <div style="border: 1px solid red;"> <div style="b ...

  4. 深入理解CSS中的margin负值

    前面的话 margin属性在实际中非常常用,也是平时踩坑较多的地方.margin折叠部分相信不少人都因为这样那样的原因中过招.margin负值也是很常用的功能,很多特殊的布局方法都依赖于它.它看似简单 ...

  5. 深入理解css中position属性及z-index属性

    深入理解css中position属性及z-index属性 在网页设计中,position属性的使用是非常重要的.有时如果不能认识清楚这个属性,将会给我们带来很多意想不到的困难. position属性共 ...

  6. 理解与应用css中的display属性

    理解与应用css中的display属性 display属性是我们在前端开发中常常使用的一个属性,其中,最常见的有: none block inline inline-block inherit 下面, ...

  7. 深入理解css中position属性及z-index属性 https://www.cnblogs.com/zhuzhenwei918/p/6112034.html

    深入理解css中position属性及z-index属性 请看出处:https://www.cnblogs.com/zhuzhenwei918/p/6112034.html 在网页设计中,positi ...

  8. css中的定位属性position(转)

    css中的定位属性position   同样的也是上课的时候发现学生难以理解的一些问题拿出来记录一下,希望帮助初学者. 在css中定位属性position的运用在页面中是很常用的,特别是一些结合js来 ...

  9. CSS中上下margin的传递和折叠

    CSS中上下margin的传递和折叠 1.上下margin传递 1.1.margin-top传递 为什么会产生上边距传递? 块级元素的顶部线和父元素的顶部线重叠,那么这个块级元素的margin-top ...

随机推荐

  1. How to remove a batch of VMs and related Disks

    Foreword Need to remove a batch of VMs, which named with same prefix or belong to same Cloud Service ...

  2. mac 设置阿里企业邮箱

    接收邮件服务器:pop3.mxhichina.com或pop3.您的域名,端口:110 发送邮件服务器:smtp.mxhichina.com或smtp.您的域名,端口:25 IMAP协议设置 接收邮件 ...

  3. Windows10一周年庆典壁纸

    example: 下载:http://pan.baidu.com/s/1b55D5k

  4. jqMobile中的dialog和popup的区别

    主要区别是:dialog默认含回退按钮.并且dialog在1.4版中已经过时,1.5中将会移除. 下面是 原文1: Using a Dialog Window as a Popup A jQuery ...

  5. (01)javascript 数据类型

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  6. bootstarp风格的toggle效果分享

    最近在写项目的时候想要一个这样的效果: 我知道这个效果在 flat-ui中有, 但是我又不想引用一整个flat-ui; 这个效果依赖html5的transition, 所以浏览器兼容成问题: 从fla ...

  7. C# 公历转农历

    /// <summary>     /// LunDay 的摘要说明.     /// 用法说明     /// 直接调用即可,比较简单     /// </summary> ...

  8. 【HDU 5833】Zhu and 772002(异或方程组高斯消元)

    300个最大质因数小于2000的数,选若干个它们的乘积为完全平方数有多少种方案. 合法方案的每个数的质因数的个数的奇偶值异或起来为0. 比如12=2^2*3,对应的奇偶值为01(2的个数是偶数为0,3 ...

  9. Using the rJava package on Win7 64 bit with R

    加载 rJava 包报错: > library(rJava) Error : loadNamespace()里算'rJava'时.onLoad失败了,详细内容: 调用: fun(libname, ...

  10. Day_6作业_模拟人生

    as #!/usr/bin/env python # encoding: utf-8 class wisdom(object): def __init__(self,n,g): self.n = n ...