一、Margin的特性
margin始终是透明的。
margin通过使用单独的属性,可以对上、右、下、左的外边距进行设置。即:margin-top、margin-right、margin-bottom、margin-left。
外边距的 margin-width 的值类型有:auto | length | percentage
也可以使用简写的外边距属性同时改变所有的外边距:margin: top right bottom left;(eg: margin:10px 20px 30px 40px) 记忆方式是元素周围正上方顺时针“上右下左”记忆。
并且规范还提供了省略的数值写法,基本如下:
1、如果margin只有一个值,表示上右下左的margin同为这个值。例如:margin:10px; 就等于 margin:10px 10px 10px 10px;
2、如果 margin 只有两个值,第一个值表示上下margin值,第二个值为左右margin的值。例如:margin:10px 20px; 就等于 margin:10px 20px 10px 20px;
3、如果margin有三个值,第一个值表示上margin值,第二个值表示左右margin的值,第三个值表示下margin的值。例如:margin:10px 20px 30px; 就等于 margin:10px 20px 30px 20px;
4、如果margin有四个值,那这四个值分别对应上右下左这四个margin值。例如:margin:10px 20px 30px 40px;
在实际应用中,个人不推荐使用三个值的margin,一是容易记错,二是不容易日后修改,一开始如果写成margin:10px 20px 30px;日后需求改动为上10px,右30px,下30px,左20px,你不得不还是得把这个margin拆开为margin:10px 30px 30px 20px;费力且不讨好,不如一开始就老老实实的写成margin:10px 20px 30px 20px;来的实在,不要为了现在节省俩个字节而让日后再次开发的成本上升。
垂直外边距合并问题
别被上面这个名词给吓倒了,简单地说,外边距合并指的是,当两个垂直外边距相遇时,它们将形成一个外边距。合并后的外边距的高度等于两个发生合并的外边距的高度中的较大者。你可以查看W3Shool CSS外边距合并了解这个基本知识。
实际工作中,垂直外边距合并问题常见于第一个子元素的margin-top会顶开父元素与父元素相邻元素的间距,而且只在标准浏览器下(FirfFox、Chrome、Opera、Sarfi)产生问题,IE下反而表现良好。例子可以查看下面代码(IE下表现“正常”,标准浏览器下查看出现“bug”):
如果按照CSS规范,IE的“良好表现”其实是一个错误的表现,因为IE的hasLayout渲染导致了这个“表现良好”的外观。而其他标准浏览器则会表现出“有问题”的外观。好了,如果你读过了上面W3Shcool的CSS外边距合并的文章后,就很容易讨论这个问题了。这个问题发生的原因是根据规范,一个盒子如果没有上补白(padding-top)和上边框(border-top),那么这个盒子的上边距会和其内部文档流中的第一个子元素的上边距重叠。
再说了白点就是:父元素的第一个子元素的上边距margin-top如果碰不到有效的border或者padding.就会不断一层一层的找自己“领导”(父元素,祖先元素)的麻烦。只要给领导设置个有效的 border或者padding就可以有效的管制这个目无领导的margin防止它越级,假传圣旨,把自己的margin当领导的margin执行。
对于垂直外边距合并的解决方案上面已经解释了,为父元素例子中的middle元素增加一个border-top或者padding-top即可解决这个问题。
一般说来这个问题解释到这里,大多数文章就不会再深入下去了,但作为一名实战开发者,最求的是知其然知其所以然,原本使用margin-top就是为了与父元素隔开距离,而按照你这么一个解法,其实是一种“修复”,为了“弥补修复”这个父子垂直外边距合并这个CSS规范“Bug”,而强制在父元素上使用border-top和padding-top,不舒服,也不容易记住,下次再发生这样的情况还是会忘记这条准则,而且在页面设计稿里如果不需要border-top加个上边框,这么一加反而画蛇添足,为以后修改留下隐患。
为什么一定要用border-top,padding-top去为了这么一个所谓的标准规范而多写这么一行代码呢?答案你可以参考另外一篇文章用Margin还是用Padding里找到答案。
用Margin还是用Padding
何时应当使用margin:
需要在border外侧添加空白时。
空白处不需要背景(色)时。
上下相连的两个盒子之间的空白,需要相互抵消时。如15px + 20px的margin,将得到20px的空白。
何时应当时用padding:
需要在border内测添加空白时。
空白处需要背景(色)时。
上下相连的两个盒子之间的空白,希望等于两者之和时。如15px + 20px的padding,将得到35px的空白。
个人认为:margin是用来隔开元素与元素的间距;padding是用来隔开元素与内容的间隔。margin用于布局分开元素使元素与元素互不相干;padding用于元素与内容之间的间隔,让内容(文字)与(包裹)元素之间有一段“呼吸距离”。
二、margin 的基本写法
外边距的 margin-width 的值类型有:auto | length | percentage
percentage:百分比是由被应用 box 的containing block(注:一个元素的 containing block 是该元素产生的 box(es)在计算位置和大小时参考的一个矩形)的大小所决定。对于 margin-top 和 margin-bottom 也同样成立。
margin 的默认值为 0,并且 margin 支持负值。
上面我们曾提到属性 margin 可以用来同时指定 box 的四边外边距。如果属性 margin 有四个值,那么值将按照上-右-下-左的顺序作用于四边,即从元素的上边开始,按照顺时针的顺序围绕元素。表达式如下:
四个数值中间以空格分隔。效果等同于:
并且规范还提供了省略的数值写法,基本原则如下:
如果没有 left 值,则使用 right 代替;
如果没有 bottom 值,则使用 top 代替;
如果没有 right 值,则使用 top 值代替。
根据这些基本原则,我们可以有三种省略方式,但不管怎样省略 margin 的数值都会大于等于一个,而 margin 的默认数值是从 top 开始至 left 结束,那么对于省略的具体情况,我们可以从 left 反推理回去。
1、如果 margin 只有三个值,按照值的顺序为 margin:top right bottom; 缺少了 left,根据原则,则 left 的值有 right 来代替。margin:10px 20px 30px; 就等于 margin:10px 20px 30px 20px;
2、如果 margin 只有两个值,按照值的顺序为 margin:top right; 缺少了 bottom 和 left,根据原则 left 的值由 right 来代替,bottm 的值由 top 来代替。margin:10px 20px; 就等于 margin:10px 20px 10px 20px;
3、如果 margin 只有一个值,按照值的顺序为 margin:top; 缺少了 bottom、left 和 right,根据原则 left 的值由 right 来代替,bottom 的值由 top 来代替,right 的值右 top 来代替,也就是说 left 的值也由 top 来代替。margin:10px; 就等于 margin:10px 10px 10px 10px;
三、margin的解析逻辑
目前我们已经了解到了 margin 的基本特性和基本写法,但对元素 margin 的基本解析逻辑还是很模糊,到底 margin 的 top、right、bottom、left 都是以什么为基准来促使 box model 形成。为了形象,易懂的对 margin 的逻辑进行说明,下面讲解的过程中,将引入 W3C 上没有的参考线的说法。何谓参考线?参考线就是 margin 移动的基准点,此基准点相对于 box 是静止的。而 margin 的数值,就是 box 相对于参考线的位移量。
在 margin 中 top、right、bottom、left 的参考线并不一致为一类,而是分为了两类参考线,top 和 left 的参考线属于一类,right 和bottom 的参考线属于另一类。那他们到底各以什么为参考线呢?top 以 containing block 的 content 上边或者垂直上方相连元素 margin 的下边为参考线垂直向下位移;left 以 containing block 的 content 左边或者水平左方相连元素 margin 的右边为参考线水平向右位移。right 以元素本身的 border 右边为参考线水平向右位移;bottom 以元素本身的border 下边为参考线垂直向下位移。从上我们可以看到 top 和 left 都是以外元素为参考,而 right 和 bottom 以本元素为参考。上面的位移方向是指 margin 数值为正值时候的情形,如果是负值则位移方向相反。
或许理论听起来比较枯燥,我们举例说明一下:
如上代码,很简单,为了方便我们看到效果,我们给 div 设置了宽度和高度以及背景色。
现在我们给 div 的样式加上 margin 属性,比如:
这时候 margin 的解析逻辑是怎样的呢?首先我们要搞清 div 的和周边元素的关系,div 没有相连元素,而此时 div 的 containing block 是 body 产生的 block box。则根据上面介绍的参考线原理,div 的左外边距以 containing block 的 content 左边为参考线,及此时以 body 的 content 左边为参考线进行水平向右位移,位移的大小为 40px,同理,上边距以 body 的 content 上边为参考线进行垂直向上位移 10px(负值和正值的方向相反),下边距依照现在 div 的 borer 下边(此时的 div 已经经过上边距位移过了)垂直向上位移 30px(此时,margin 不会改变 box 的 border 内的物理大小,但会改变 box 的逻辑大小,即:以此 box 的 margin 的下边为参考的元素,不是从 box 的物理位置开始的,而是从逻辑位置开始),右边距依照现在 div 的 borer 右边(此时的 div 已经经过左边距位移过了)水平向右位移 20px。或许有朋友问你分析的顺序怎么和 margin 表达式中出现的顺序不一样?如果按照 margin 表达式中出现的顺序来分析,结果是一样的,只是为了更好的方便大家的理解而没有按照表达式的顺序来分析。
用 margin 最后的实际显示大小的到底是怎么样呢,或许有朋友也比较疑惑,我暂时用逻辑大小和物理大小来区分(其实上面已用到此概念),到底什么是逻辑大小,什么是物理大小呢?!具体可以看图,物理大小指的是除去 margin,也就是包含 border 以内的 box 大小,而逻辑大小,则是 box 通过 margin 解析规则解析后得到的大小(这或许可以解释为什么IE5会错误解析盒模型)。在上图中,box 的实际显示的宽度等于 box 的逻辑大小,而 box 实际显示的高度等于 box 的物理大小,这说明 box 实际显示的大小可能是 box 的逻辑大小,也可能是 box的 物理大小,规则到底是怎样的——
box 的实际大小 = box 的物理大小 + 正的 margin
这仅对元素本身有效,对于其后面的相关元素,他们则只以 margin 的逻辑大小为准则,进行布局。
有朋友反应,听得很迷糊,越看越不懂,如果你对具体的理解过程不感兴趣的话,那记住下面我总结的结论就可以了,XD
结论:
box 最后的显示大小等于 box 的 border 及 border 内的大小加上正的 margin 值。而负的 margin 值不会影响 box 的实际大小,如果是负的 top 或 left 值会引起 box 的向上或向左位置移动,如果是 bottom 或 right 只会影响下面 box 的显示的参考线。