简单而不单纯的height
width和height是CSS世界中同一类型的魔法师,都是直接限定元素尺寸的。所以,它们共用一套“盒尺寸”模型,box-sizing的解释也是类似的。但是,它们在不少地方还是有明显区别的,其中之一就是height:auto和width:auto简单而单纯得多。
关于height:auto
在CSS中,默认流的方向是水平的,宽度是稀缺的,高度是无限的。因此,宽度的分配规则就比较复杂,高度就显得比较随意。比方说,一块砖头5cm高,请问,10块砖头摞在一起多高?很简单,50cm。height:auto的表现也基本上就是这个套路:有几个元素盒子,每个多高,然后加在一起,就是最终的高度值了。
当然,涉及具体场景,就会有其他的小故事了。比方说,元素float容器高度没了,或者是margin直接穿过去,高度比预期的矮了。这个其实不是height的问题。关于这一点,容后再说。
关于height:100%
height和width还有一个比较明显的区别就是对百分比单位的支持。对于width属性,就算父元素width为auto,其百分比值也是支持的;但是,对于height属性,如果父元素height为auto,只要子元素在文档流中,其百分比值完全就被忽略了。例如,下面的代码:
div {
widht: 100%; // 这个是多余的
height: 100%; // 这个是无效的
background: url(bg.jpg);
}
运行之后,在浏览器中,这个<div>高度永远是0,哪怕其父级<body>塞满了内容也是如此。事实上,只需要如下设置才行:
html, body {
height: 100%;
}
如果仅仅设置<body>也是不行的,因为此时的<body>也没有具体的高度值:
body {
/* 子元素height: 100%依旧无效 */
}
只要经过一定的实践,我们都会发现对于普通文档流中的元素,百分比高度值要想起作用,其父级必须有一个可以生效的高度值!但是,怕是很少有人思考过这样一个问题:为何父级没有具体高度值的时候,height: 100%会无效?
有一种看似合理的说法:如果父元素height:auto子元素还支持height:100%,则父元素的高度很容易陷入死循环,高度无限。例如,一个<div>元素里面有一张vertical-align为bottom同时高度为192像素的图片,此时,该<div>高度就是192像素,假设此时插入一个子元素,高度设为100%,如果此时height:100%可以计算,则子元素也该是192像素。但是,父元素height为auto,岂不是现在高度要从原来的192像素变成384像素,然后height:100%的子元素高度又要变成384像素,父元素高度又双倍……死循环了。
实际上,这种解释是错误的,大家千万别被误导。证据就是宽度也存在类似场景,但并没有死循环。例如,在下面的例子中,父元素采用“最大宽度”,然后有一个inline-block子元素宽度100%:
/* HTML code */
<div class="box">
<img src="pic.jpg">
<span class="text">红色背景是父级元素</span>
</div>
/* CSS code */
.box {
display: inline-block;
white-space: nowrap;
background-color: #cd0000;
}
.text {
display: inline-block;
width: 100%;
background-color: #34538b;
color: #fff;
}
如果按照上面的“高度死循环”的解释,这里也应该“宽度死循环”,因为后面的inline-block元素按照我们的理解应该会让父元素的宽度进一步变大。但实际上并没有,宽度范围可能超出你的预期。父元素的宽度就是图片加文字内容的宽度之和。

为什么会这样表现呢?
要明白其中的原因要先了解浏览器渲染的基本原理。首先,先下载文档内容,加载头部的样式资源(如果有的话),然后按照从上而下、自外而内的顺序渲染DOM内容。套用本例就是,先渲染父元素,后渲染子元素,是有先后顺序的。因此,当渲染到父元素的时候,子元素的width:100%并没有渲染,宽度就是图片加文字内容的宽度;等渲染到文字这个子元素的时候,父元素宽度已经固定,此时的width:100%就是已经固定号的父元素的宽度。宽度不够怎么办?溢出就好了,overflow属性就是为此而生的。
同样的道理,如果height支持任意元素100%,也是不会死循环的。和宽度类似,静态渲染,一次到位。
那问题又来了:为何宽度支持,高度就不支持呢?规范中其实给出了答案。如果包含块的高度没有显示指定(即高度由内容决定),并且该元素不是绝对定位,则计算值为auto。一句话总结就是:因为解释成了auto。要知道,auto和百分比计算,肯定是算不了的:‘auto’ * 100/100 = NAN。但是,宽度的解释却是:如果包含块的宽度取决于该元素的宽度,那么产生的布局在CSS2.1中是未定义的。
如何让元素支持height:100%效果
(1)设定显示的高度值。这个没什么好说的,例如,设置height:600px。或者可以生效的百分比值高度。
(2)使用绝对定位。例如:
div {
height: 100%;
position: absolute;
}
此时的height:100%就会有计算值,即使祖先元素的height计算为auto也是如此。需要注意的是,绝对定位元素的百分比计算和非绝对定位元素的百分比计算是有区别的,区别在于绝对定位的宽高百分比计算是相对padding box的,也就是说会把padding大小值计算在内,但是,非绝对定位元素则是相对于content box计算的。
可以看一个例子,对比以下:
.box1 {
height: 160px;
padding: 30px;
box-sizing border-box;
background-color: #beceeb;
}
.child1 {
height: 100%;
background-color: #cd0000;
}
.box2 {
height: 160px;
padding: 30px;
box-sizing: border-box;
background-color: #beceeb;
position: relative;
}
.child2 {
height: 100%;
width: 100%;
background-color: #cd0000;
position: absolute;
}
可以看到,非定位元素的宽高百分比计算不会将padding计算在内。
