百分比在屏幕自适应是我们常用,但是很多时候某个CSS属性的百分比计算值,并非如我们所想象的那样子。前段时间有位同学分享了一篇关于margin/padding自适应布局的文章,看完后我去w3.org查了下margin
和padding
百分比计算的注意事项,描述如下:
Note that in a horizontal flow, percentages on ‘margin-top’ and ‘margin-bottom’ are relative to the width of the containing block, not the height (and in vertical flow, ‘margin-left’ and ‘margin-right’ are relative to the height, not the width).[1]
Note that percentages on ‘padding-top’ and ‘padding-bottom’ are relative to the width of the containing block, not the height (at least in a horizontal flow; in a vertical flow they are relative to the height).[2]
水平流?垂直流?那是甚么鬼?之前我一直不明白这两者何意,直到最近看CSS权威指南,讲到direction
的时候提到了CSS Writing Modes Level 3里的writing-mode
,查了官方文档后才知道,CSS3以后就有了定义内容书写方向的规范。
什么是块级流方向
块级流方向就是块级盒子在块级格式化上下文中以何种方向来进行顺序排列。这里要注意的一点是对于英文(也是简体中文)这种从上至下从左至右书写的语言,writing-mode
和direction
分别会被默认设为horizontal-tb
和ltr
。简言之,块级流方向包含两种:一种是水平流,一种是垂直流。另外在CSS权威指南P171有提到,我们常见的margin
的初始值是0,但是我们看到的大都是靠在左上方的,因为在英文语言的书写顺序、也就是块级流方向下,margin-right
和margin-bottom
被默认强制设为auto了。如果不明白这些默认的强制格式化属性规范,很多时候我们做出来页面的效果可能会有点不合本意。这时我才渐渐意识到文本语言码识别lang
和字符码识别charset
在多语言情境下的重要性,另外关于FBC的内容还我也还未深入了解(这里挖个坑,以后填),请参看参考目录部分。
如何设置块级流方向
direction
属性只是影响的行内类型内容的书写方向,而writing-mode
则是可以直接影响块级元素的布局。horizontal-tb
是我们常用页面的默认设定,决定了内容的水平方向书写和块级流方向的从上往下推进;vertical-rl
和vertical-lr
则是部分语言的书写方向,这两个属性值决定了内容的垂直方向书写以及块级流方向分别是从右往左推进和从左往右的推进,比如,古汉字应用中最常见的是圣旨是从右向左推进、从上往下书写的,现代的日语也有这种格式的。
对百分比计算的影响
首先,先明确这里要讨论的是块级元素的水平流和垂直流对margin
、padding
、width
、height
的百分比属性值的计算值的影响。
然后,准备好测试代码(可以去我的github下找到ver_hor_flow.html和ver_hor_flow.css):
<div id="outer">test contet
<div id="inner">test content</div>
</div>
#outer {
background-color: fuchsia;
height: 300px;
width: 500px;
}
#inner {
background-color: lime;
margin: 1% 8% 2% 5%;
padding: 1% 8% 2% 5%;
height: 10%;
width: 50%;
}
这里,我们对内部的子元素直接设置了宽高以便于,观察父元素容器的水平流和垂直流对子元素宽高的影响。但是如果不设置宽高,则子元素的宽高默认会是内容宽高,而内容高(垂直流中变成横向的了,以width衡量)由行高决定,而行高则在字体大小的基础上乘以一个浏览器默认的缩放因子来得到,字体大小也是有一个浏览器默认的计算值。比如我的浏览器默认是font-size:16px;
以及line-height:21px;
,这个21px是字体大小与一个缩放因子相乘后的结果,内容高度就是它了。Anyway,下面继续。
父元素容器水平流
对父元素,默认设置writing-mode: horizotal-tb;
,水平流。
测试图:margin-top
和padding-top
:500px乘以1%=5pxmargin-right
和padding-right
:500px乘以8%=40pxmargin-bottom
和padding-bottom
:500px乘以2%=10pxmargin-left
和padding-left
:500px乘以5%=25pxwidth
:500px乘以50%=250pxheight
:300px乘以10%=30px
小结:可以看出,子元素margin
和padding
是以父元素的width
为基数计算的,而子元素的width
和height
是对应以父元素的width
和height
为基数计算的。
父元素容器垂直流
对父元素设置writing-mode:vertical-lr;
,垂直流。
测试图:margin-top
和padding-top
:300px乘以1%=3pxmargin-right
和padding-right
:300px乘以8%=24pxmargin-bottom
和padding-bottom
:300px乘以2%=6px,这里margin-bottom
的258px是因为我们设置了height:10%;
,由于margin
只是设置的最小值,一旦不足他会自动补上剩余的部分(300px-3px-3px-30px-6px=258px)。如果没设置height
就会“正常”了。(这里要考虑到“过度受限”规则影响,也就是一个盒子的计算值相互矛盾的情况下,进行的一种“优先级”权衡。这里的自动补充计算值其实是因为对于水平流、从上往下推进的语言,实际上的margin-bottom
会被强制设为auto,至于为何margin-right又正常呢?嗯,我也还在深入了解这个影响计算规则的“过度受限overconstrained”。)margin-left
和padding-left
:300px乘以5%=15pxwidth
:500px乘以50%=250pxheight
:300px乘以10%=30px
小结:设置垂直流以后,margin
和padding
的百分比计算基数变成了父元素的高度(height:300px;
),而子元素的width
和height
的百分比计算仍然是对应以父元素的width
和height
为基数计算的。
这里只测试了垂直流中从右向左推进时,各属性值的计算,另一种从左向右推进的各属性值计算结果是一样的,在此不赘述。
子元素垂直流
上面都是对作为容器的父元素进行块级流方向设置,如果只是对于子元素设置呢?
对内部的子元素设置writing-mode: vertical-lr;
父元素不做其他设置,即默认。
小结:子元素的宽高和外边距、内边距都没有改变,也就是说子元素改变的块级流方向不影响本身margin
、padding
、width
、height
的计算值。
2D变形中旋转的影响
2D变形中有个rotate()
函数可以扭转一个元素的摆放方向,那这个函数的设置会不会对子元素本身的margin
、padding
、width
、height
计算值造成影响呢?
设置transform:rotate(-90deg);
小结:变形只是改变了子元素的表现形式,但是并未改变子元素的百分比计算值。
--------------------------------------割----------------------------------
两天后,回过头看了下,这部分还要加个父元素的测试才算完整。不过结果是一样的:各属性的百分比数值计算并不受影响。我的Github上的测试代码,会同步更新。
边框不可设置百分比
查看边框的官方标准可知,边框不能设置百分比属性值,但是有相对属性值em、ex等,它们的计算都是以当前字体大小为基数。
box-sizing
属性的影响
这个属性只会影响到设置width
和height
后,内容区的大小,它对于外边距和内边距的计算不影响。
总结
在常用的盒模型百分比计算中,子元素的width
和height
始终跟随父元素对应的宽高计算;而子元素的margin
和padding
则要考虑当前文档的块级流方向是水平流还是垂直流,如果是水平流,则以父元素的width
为基数计算百分比,如果是垂直流则以父元素的height
为基数计算百分比。单个子元素改变块级流方向以及设置变形都不改变父元素下子元素的块级流方向,不影响百分比计算。边框不可设置百分比。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。