面试官问:假设一个div,宽400px,高200px,他有个子div的margin:10%,你来算下他的margin 的 top, right, bottom, left 是多少?
当时觉得事不单纯,但是没有其他的印象,所以就直接就回答了:20px 40px 20px 40px。直到后来回去自己做了下测试,才知道自己的错误。下面上DEMO,从DEMO中可以很直观的看到margin值都一样的长度,这里为40px 40px 40px 40px,也许这个结果令你吃惊,你对margin的百分比或许有了自己的想法。
margin:百分比的计算基于生成框的包含块(父元素)的width(margin-top/bottom也是如此)。 padding同理
对于margin-left和margin-right很好理解,但是为什么margin-top和margin-bootom也是相对于父元素width而不是height呢
WHY 对于margin/padding-top/bottom 的百分比之所以按照 width 计算,目前主要有这么几种解释
(1)相对于height计算会引起无限循环
正常流中的大多数元素都会足够高以包含其后代元素(包括外边距),如果一个元素的上下外边距是父元素的height的百分数,就可能导致一个无限循环,父元素的height会增加,以适应后代元素上下外边距的增加,而相应的,上下外边距因为父元素height的增加也会增加,如此循环。
(2)基于排版的需求
之所以按照同一个width来计算,是为了要横向和纵向2个方向都创建相同的margin/padding,如果它们的参照物不一致,那用百分比就无法得到垂直和水平一致的留白。
至于为什么是width而不是height?这是因为CSS的基础需求是排版,因此水平和垂直方向其实并不是同等权重的,更精确的说,因为我们常见的书写方向是横排文字,我们排版的水平宽度是一致的,而垂直方向上是可以向下无限延展的。对于竖排文字则相关, margin/padding-* 都按照 height计算。
对于受书写模式或者说排版方向影响还有一些其他的特性,比如说传统横排时,两个块状盒子margin在垂直方向上的 collapse(合并),段落间的空白进行 collapse 是常见和方便的。此时对于竖排,则是margin在水平方向上的collapse(合并)。
@胡文斌 给出的stackoverflow上的这个答案与题主的猜想都是不正确的。margin/padding-top/bottom 的百分比之所以按照 width 计算,其实理由很简单,就是要匹配主要的 use cases。那就是——要构建在纵横两个方向上相同的 margin/padding。如果两个百分比的相对方式不同,那用百分比就无法得到垂直和水平一致的留白。
有人也许会问,为什么不是垂直方向上的 height 而是水平方向的 width?这其实容易理解。因为 CSS 的基本模型是着重于“排版”的需求,因此水平和垂直方向其实并不是同等权重的,更精确的说,是文字书写方向决定的。常见的横排文字时,我们排版的出发点是水平宽度一定,而垂直方向上是可以无限延展的。竖排文字则相反。所以在竖排文字时,margin/padding-* 其实就都按照 height 而不是 width 计算了。类似的且大家更熟悉的是 margin-top/bottom 在垂直方向上的 collapse(或者当竖排文字时是 margin-left/right 水平方向上的 collapse)。为什么只有垂直方向 collapse 而水平就不呢?因为在典型的排版中,段落间的空白进行 collapse 是常见和方便的。而反过来水平方向上就几乎没有那样的需求(只有表格在两个方向上有对称的 border collapse 的需求)。同样的,在排版中,横向百分比控制是常见的需求,但是纵向其实很少这样的需求。有这样需求的其实是GUI界面布局,布局和排版的区别在这个答案(在 CSS 布局中,用 float 好还是用 position 好?分别有什么优势?)我也提到过。
至于说死循环问题,其实这不是根本原因。大家可以想想 width 为什么就不存在死循环了呢?
BTW,在现代web应用中,其实我们有更多的纵向横向布局分割需求,这是传统的百分比不能很好满足的,所以CSS3实际上加入了 vw 和 vh 单位(相对于viewport的宽度和长度百分比),这比较好的解决了传统CSS中margin/padding的百分比所不能满足的那些需求。