在我们编写CSS的时候,经常会用到百分比赋值(%)实现自适应。在正常的流顺序下宽度的%没问题,但是高度的%经常不生效,这是为何?
为何 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%:
|
|
要明白其中的原因要先了解浏览器渲染的基本原理。首先,先下载文档内容,加载头部的样式资源(如果有的话),然后按照从上而下、自外而内的顺序渲染 DOM 内容。套用本例就是,先渲染父元素,后渲染子元素,是有先后顺序的。因此,当渲染到父元素的时候,子元素的width:100%并没有渲染,宽度就是图片加文字内容的宽度;等渲染到文字这个子元素的时候,父元素宽度已经固定,此时的 width:100%就是已经固定好的父元素的宽度。宽度不够怎么办?溢出就好了, overflow 属性就是为此而生的。
同样的道理,如果 height 支持任意元素 100%,也是不会死循环的。和宽度类似,静态渲染,一次到位。
规范中解释
那问题又来了:为何宽度支持,高度就不支持呢? 规范中其实给出了答案。如果包含块的高度没有显式指定(即高度由内容决定),并且该元素不是绝对定位,则计算值为auto。 一句话总结就是:因为解释成了 auto。要知道, auto 和百分比计算,肯定是算不了的:
但是,宽度的解释却是:如果包含块的宽度取决于该元素的宽度,那么产生的布局在 CSS 2.1中是未定义的。
这里和高度的规范定义就区别明显了,高度明确了就是 auto,高度百分比计算自然无果, width 却没有这样的说法,因此,就按照包含块真实的计算值作为百分比计算的基数。
如何让元素支持 height:100%效果
这个问题的答案其实上面的规范已经给出了,即有两种方法:
- 设定显式的高度值。
|
|
- 使用绝对定位。
|
|
此时的 height:100%就会有计算值,即使祖先元素的 height 计算为auto 也是如此。需要注意的是,绝对定位元素的百分比计算和非绝对定位元素的百分比计算是有区别的,区别在于绝对定位的宽高百分比计算是相对于 padding box 的,也就是说会把 padding 大小值计算在内,但是,非绝对定位元素则是相对于 content box 计算的。
非定位元素的宽高百分比计算不会将 padding 计算在内,这两种 height:100%生效方法的评价是:显式高度方法中规中矩,意料之中;绝对定位方法剑走偏锋,支持隐式高度计算,给人意外之喜,但本身脱离文档流,使其仅在某些场景有四两拨千斤的效果。