重拾CSS规范之margin

好久没写博客了,甚是惭愧啊,md语法都快忘了。最近一直在忙着巩固基础,实在是厌倦那种似懂非懂的感觉。有的时候bug出来了,拿别人的代码可能一下子就解决了,可是知识面太零碎化。这篇文章不会涉及margin基本属性,因为这些网上都有。本文内容量不会特别大,但是里面的知识点很多人在实际开发中却会混淆。

margin有效性

margin对 display:table; 系列(这其中不包含 table-caption, table 和 inline-table) 以外的所有元素有效

margin-top 和 margin-bottom 对不可替换的内联元素无效

margin百分比值

百分比根据生成盒的包含块的width来计算。

我们来看看关于包含块的几种情况:

如果该元素的position是 relative 或者 static,包含块由其最近的块容器祖先盒的content边形成

如果元素具有 position: fixed,包含块由连续媒体的视口或者分页媒体的页区建立

如果元素具有 position: absolute,包含块由最近的 positionabsoluterelative或者 fixed 的祖先建立,按照如下方式:

  1. 如果该祖先是一个内联元素,包含块就是环绕着为该元素生成的第一个和最后一个内联盒的 padding box 的边界框。
  2. 否则,包含块由该祖先的 padding 边形成

margin auto探讨

我们是否有想过一个有固定宽度的div元素设置了 margin: auto; 为什么可以水平居中显示?为什么有固定高度却无法垂直居中显示?

why can 水平居中

常规流中的块级不可替换元素的规则中包含这样两个规则:

  1. ‘margin-left’ + ‘border-left-width’ + ‘padding-left’ + ‘width’ + ‘padding-right’ + ‘border-right-width’ + ‘margin-right’ = 包含块的宽度
  2. 如果’margin-left’和’margin-right’都是’auto’,那么它们的应用值相等。

举个栗子,假设 div 设置了固定宽度, paddingborder 为零,当我们设置 margin: auto; 时,浏览器会设置 margin-left 等于 margin-right,并且解方程组求出正确的margin-leftmargin-right 值。

只要常规流中的div有固定宽度,并且 paddingborder 左右两边的数值大小一样,设置了 margin: 0 auto; 就能让其水平居中显示。

why can’t 垂直居中

CSS2.1规范文档10.6.3节指出: ‘overflow’ 计算值为 ‘visible’ 时常规流中的块级不可替换元素

如果’margin-top’或者’margin-bottom’为’auto’,其应用值为 0。

所以说,管你有没有设定高度,你都会把你的 margin 上下值设置为 0。也就是垂直方向上 div 原地不动!

What else can 水平/垂直居中 by ‘margin: auto’

除了本节的第一种情况外,还有一种情况,那就是 绝对定位元素

它不仅能够水平居中,同样能够垂直居中。

上面 top/bottom/left/right 我都设置的 0 ,当然也可以设置成非零元素,只需要让数值两两对称就行了,但是这样不够安全。举个栗子,有人作死,top/bottom 的值放得太大了,top + bottom + height + border + padding 超过了 包含块的高度,那咋办呢??? margin 不就要变成负值了吗??? 不会的,这时候,浏览器会忽略 bottom 值, margin-top/margin-bottom 置 0,根据方程式重新计算合适的 bottom 值,而我们里面的 div 就不会垂直居中了,它会根据 top 来定位。

所以么,能不作死就不要作死了,上面的代码示例又方便又安全。

margin合并

margin合并也可以叫做外边距叠加,这是一个简单的概念,指的就是两个或者多个盒的相邻的margin可能会合并在一起。如果还不能理解的话,我们用图示来理解一下。

当一个元素出现在另一个元素上面时,第一个元素的底外边距与第二个元素的顶外边距发生叠加。

Margin Collapse Losted

当一个元素包含在另一个元素中时,它们的顶外边距或者底外边距也会发生叠加。

Margin Collapse Losted

甚至外边距还能与自身进行叠加。如果一个空元素,上下方向有外边距,但没有边框和内边距,这时候,上下外边距就会相遇,自然而然的叠加了。

Margin Collapse Losted

如果这个外边距又遇到了其他元素的外边距(margin相邻),它们还能继续叠加。

Margin Collapse Losted

O__O “…看来margin的世界里也会有小三小四的存在。

那我们有没有想过 CSS 工作组为什么会设立这么一个 bug 般的存在!这是为了服务段落元素 p 啊。

我们常见的段落与其他元素都会有间距,这是因为,用户代理给他们设置了默认margin值。可那为什么两个段落相遇,间距却没有拉大呢?这就是用到了我们上面所说的前后两个div,它们的底外边距和顶外边距叠加在一起了,共享一个外边距,自然就不会拉大了。

不是所有相邻的margin相邻都可以合并!!!

margin合并规则

  1. 水平方向的 margin 不会合并

  2. 一个浮动的盒与任何其它盒之间的 margin 不会合并(甚至一个浮动盒与它的流内子级之间也不会)

  3. 建立了新的块格式化上下文的元素(例如,浮动盒与 ‘overflow’ 不为 ‘visible’ 的元素)的 margin 不会与它们的流内子级合并

  4. 绝对定位的盒的 margin 不会合并(甚至与它们的流内子级也不会)

  5. 内联盒的 margin 不会合并(甚至与它们的流内子级也不会)

  6. 一个流内块级元素的 bottom margin 总会与它的下一个流内块级兄弟的 top margin 合并,除非兄弟有空隙

  7. 一个流内块级元素的 top margin 会与它的第一个流内块级子级的 top margin 合并,如果该元素没有 top border ,没有 top padding 并且该子级没有空隙

  8. 一个 ‘height’ 为 ‘auto’ 并且 ‘min-height’ 为 0 的流内块级盒的 bottom margin 会与它的最后一个流内块级子级的 bottom margin 合并,如果该盒没有 bottom padding 并且没有 bottom border

  9. 盒自身的 margin 也会合并,如果 ‘min-height’ 属性为 0 ,并且既没有 top 或者 bottom border ,也没有 top 或者 bottom padding ,并且其 ‘height’ 为 0 或者 ‘auto’

当两个或者更多的 margin 合并时,产生的 margin 宽度为合并 margin 宽度中的最大值。至于负 margin ,就从正相邻 margin 的最大值中减去负相邻 margin 的绝对值的最大值。如果没有正 margin ,就用 0 减去相邻 margin 的绝对值的最大值。

margin常见bug

IE6双边距bug

场景: 当给父元素内第一个浮动元素设置 margin-left 或 margin-right 时 margin 加倍。
解决办法:给第一个浮动元素设置属性 display:inline;

IE6中3px偏移bug

场景: 当一个非浮动元素与一个浮动元素相邻时,他们之间会多出 3px 的间隔。如果非浮动元素没有设置高度,将使非浮动元素中的内容与其多出 3px 间隔,如果设置了高度,则是 div 之间多出了 3px 间隔。
解决方法: 设置非浮动元素 float:left; 一起浮动;或者为右边元素添加 IE6 Hack——为非浮动元素设置高度 _min-height:1%;。这时文本3px偏移会消失,但时候出现元素盒偏移,只需要再为浮动元素设置 _margin-right:-3px;就可以了

热评文章