本文依赖于一个基础却又容易混淆的css知识点:当margin/padding取形式为百分比
的值时,不管是left/right,仍是top/bottom
,都是以父元素的width
为参照物的!
也许你会说,left/right以父元素的width
为参照物好理解,可是top/bottom
为何也是以父元素的width
为参照物的呢?网上众说纷纭,关键仍是看W3C的规范:javascript
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).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).css
权威一出,记住就好,科科。html
假设有这么个场景:java
如上图所示,有这么一种用来放图片的容器,图片都是正方形(为了方便举例用正方形,实际上只要固定长宽比例便可)。
在PC端好办,容器的宽高都写死是多少px,这样即便图片加载不出来容器都不会变型。可是在移动端,因为各机型分辨率相差太大,写死px是绝对不可能的,终究还得靠百分比来实现自适应:css3
这样一来,即便图片加载速度很快,容器在图片加载先后都会有一个变型的过程,也就是俗称的“闪烁”,而若是图片加载不出来,总体布局就更是难看了。
如今问题已经出来了,就是如何作到不靠图片自己就能把容器的高度撑开。segmentfault
使用margin/padding的百分比值来解决自适应高度的关键在于:容器margin/padding的百分比参照物是父元素的宽度,而容器的width的百分比参照物也是父元素的宽度,俩属性参照物一致,那么想要把这俩属性的值统一块儿来就很简单了。
优化方案是这样的:给容器设置padding-top/padding-bottom跟width一致的值(百分比)。浏览器
#container { width: 50%; //父元素宽度的一半 background-color: red; //仅为了方便演示 } .placeholder { padding-top: 50%; //与width: 50%;的值保持一致,也就是至关于父元素宽度的一半。 }
<div id="container" class="placeholder"></div>
结果,容器的视觉效果以下:app
容器的盒子模型以下:布局
从盒子模型能够看出,虽然容器的内容高度为0,但因为有了跟内容宽度一致的padding,所以总体视觉效果上像是被撑开了。此方案浏览器兼容性很不错,惟一的缺陷是没法给容器设置max-height
属性了,由于max-height
只能限制内容高度,而不能限制padding(我原觉得设置box-sizing: border-box;
可让max-height
限制padding,不过亲测无效,明白的朋友麻烦告知一下缘由)。优化
从上面的方案看出max-height
失效的缘由是容器的高度原本就是padding撑的,而内容高度为0,max-height
没法起做用。那想要优化这一点,惟一的方法就是利用内容高度来撑开而非padding,这个方案跟消除浮动所用的方案很是类似:给容器添加一个子元素/伪元素,并把子元素/伪元素的margin/padding设为100%,使其实际高度至关于容器的宽度,如此一来,便能把容器的高度撑至与宽度一致了。因为添加子元素与HTML语义化相悖,所以更推荐使用伪元素(:after)来实现此方案。
#container { width: 50%; position: relative; background-color: red; overflow: hidden; //须要触发BFC消除margin折叠的问题 } .placeholder:after { content: ''; display: block; margin-top: 100%; //margin 百分比相对父元素宽度计算 }
<div id="container" class="placeholder"></div>
此时视觉效果上与上一方案无异,重点来看看此时容器的盒子模型:
能够看出,此时容器的内容高度与内容宽度一致,妈妈不再用担忧我没法经过max-height
来限制容器高度了。
另外,使用margin的话须要考虑margin折叠的问题(参考),padding则无此烦恼。
上述方案只说起如何不依赖容器内容来撑开容器,那么,在撑开容器后,如何给容器添加内容(图片、文本等)呢?
答案很简单,那就是利用position: absolute;
:
#container { width: 50%; position: relative; background-color: red; overflow: hidden; //须要触发BFC消除margin折叠的问题 } .placeholder:after { content: ''; display: block; margin-top: 100%; //margin 百分比相对父元素宽度计算 } img { position: absolute; top: 0; width: 100%; }
<div id="container" class="placeholder"> <img src="http://img.arrayhuang.cn/product/miya-1060079/multiple/0.jpg@1e_415w_415h_1c_0i_1o_1x.jpg" /> </div>
效果以下:
有朋友可能会问,上面提到的都是宽度与高度一致的状况,若是不一致那怎么办呢?其实自适应的重点在于,元素的宽高必须维持一个固定的比例,好比说宽高一致比例就是1:1,宽是高的两倍那就是2:1,只要这个比例是明确并且固定的,那么只须要相应地修改margin/padding的百分比值便可适应不一样的宽高比例。
固然有,好比说css3新推出的长度单位vw
,就是以屏幕宽度为参照物的,只要给元素的width和height都用上vw
单位,那width跟height就能够轻易设成同样的了,不过既然是css3,浏览器兼容性确定成问题:
自适应的精髓在于宽度,margin/padding设置百分比
弥补了元素高度没法自适应地与元素宽度保持一致的缺陷。
原文地址:https://segmentfault.com/a/1190000004231995