原文:https://segmentfault.com/a/1190000004231995

一个基础却又容易混淆的css知识点

本文依赖于一个基础却又容易混淆的css知识点:当margin/padding取形式为百分比的值时,无论是left/right,还是top/bottom,都是以父元素的width为参照物的!
也许你会说,left/right以父元素的width为参照物好理解,但是top/bottom为什么也是以父元素的width为参照物的呢?网上众说纷纭,关键还是看W3C的规范

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).

权威一出,记住就好,科科。

高度自适应占位

假设有这么个场景:

如上图所示,有这么一种用来放图片的容器,图片都是正方形(为了方便举例用正方形,实际上只要固定长宽比例即可)。在PC端好办,容器的宽高都写死是多少px,这样即使图片加载不出来容器都不会变型。但是在移动端,由于各机型分辨率相差太大,写死px是绝对不可能的,终究还得靠百分比来实现自适应:

  1. 容器宽度设个50%吧,这样一行放俩容器,各占屏幕宽度一半,没问题。

  2. 图片宽度设个100%取容器的宽度,没问题。

  3. 容器高度没法设置啊,因为容器宽高的参照物不一样,而且需求是高度与宽度一致,所以无法通过为容器高度设置百分比来达成,那就只能靠内容高度撑开了。

  4. 容器的内容高度就是图片的高度,若图片是正方形,则图片高度与图片宽度一致,也即与容器宽度一致,看起来没问题是吧?实际上,在浏览器把图片加载出来以前,图片的高度是零,那可就没办法把容器撑开了,如下图所示:

这样一来,即使图片加载速度很快,容器在图片加载前后都会有一个变型的过程,也就是俗称的“闪烁”,而如果图片加载不出来,整体布局就更是难看了。现在问题已经出来了,就是如何做到不靠图片本身就能把容器的高度撑开。

设置容器的padding-bottom/top

使用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>

结果,容器的视觉效果如下:

容器的盒子模型如下:

从盒子模型可以看出,虽然容器的内容高度为0,但由于有了跟内容宽度一致的padding,因此整体视觉效果上像是被撑开了。此方案浏览器兼容性很不错,唯一的缺陷是无法给容器设置max-height属性了,因为max-height只能限制内容高度,而不能限制padding(我原以为设置box-sizing: border-box;可以让max-height限制padding,不过亲测无效,明白的朋友麻烦告知一下原因)。

给子元素/伪元素设置margin/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设置百分比弥补了元素高度无法自适应地与元素宽度保持一致的缺陷。

巧用margin/padding的百分比值实现高度自适应的更多相关文章

  1. 巧用margin/padding的百分比值实现高度自适应(多用于占位,避免闪烁)

    本文依赖于一个基础却又容易混淆的css知识点:当margin/padding取形式为百分比的值时,无论是left/right,还是top/bottom,都是以父元素的width为参照物的!也许你会说, ...

  2. 左右margin top问题百分比值

    不想说今天心情有多差! 9点多開始发现一个"bug",需求是依据屏幕高度动态调整某个div的位置.代码大概是这种. <div style="margin-top: ...

  3. margin/padding百分比值的计算

    1.百分比介绍 一般元素的宽度用百分比值表示时,元素的总宽度包括外边距取决于父元素的width,这样可能得到"流式"页面,即元素的外边距会扩大或缩小以适应父元素的实际大小.如果对这 ...

  4. 移动端网页巧用 margin和padding 的百分比实现自适应

    一个基础却又容易混淆的css知识点 本文依赖于一个基础却又容易混淆的css知识点:当margin/padding取形式为百分比的值时,无论是left/right,还是top/bottom,都是以父元素 ...

  5. CSS 百分比 margin & padding

    前段时间我同事对于margin和padding应用百分比值似乎有些误解,觉得可能是个普遍问题,所以觉得有必要拿出来单独写一下. margin和padding都可以使用百分比值的,但有一点可能和通常的想 ...

  6. 定位(left 、right 、top 、 bottom)、padding、margin 值设为百分比值时

    定位(left .right .top . bottom): top 为例 right 为例 padding.margin : 当padding.margin 值设为百分比值时,其百分比会相对于父元素 ...

  7. 当padding,margin,top为百分比值,具体数值如何计算

    padding以及margin的四个方向设置值为百分数的时候,是以父元素的宽度为基数来进行计算. (为了保持横向和纵向方向上的margin/padding一致,但是其实也不是一定以父元素的宽度为参照物 ...

  8. CSS设置百分比值的问题

    当给元素设置width:100%:height:100% 的时候没有反应 因为,元素的宽高是根据内容来自动适应的,当设置百分比值时,是根据这个元素的父元素来确定百分比的 如果父元素没有固定的值,那就需 ...

  9. css relative设置top为百分比值

    前言: 最近在学习HTML.CSS的过程中,想模仿一下百度首页.发现搜索框这一部分与上下其它元素的空白距离可以随着窗口大小变化(效果如下图所示),于是自己研究了一下并记录下来. 效果实现 <!D ...

随机推荐

  1. 团队项目-BUG排查-ADT工程 To Android Studio 一整天的排查日记

    4-22 10:44至4-23 0:45 ①打开Eclipse从Github上Clone MathsApp到本机,报错'Unable to resolve target'android-19' ②尝试 ...

  2. rfid工作原理

    RFID的工作原理是:标签进入磁场后,如果接收到阅读器发出的特殊射频信号,就能凭借感应电流所获得的能量发送出存储在芯片中的产品信息(即Passive Tag,无源标签或被动标签),或者主动发送某一频率 ...

  3. linux 内核态调试函数BUG_ON()[转]

    一些内核调用可以用来方便标记bug,提供断言并输出信息.最常用的两个是BUG()和BUG_ON(). 当被调用的时候,它们会引发oops,导致栈的回溯和错误信息的打印.为什么这些声明会导致 oops跟 ...

  4. Java多线程 -sleep 用法详解

    阿里面试官问我这个问题,我仔细总结了一下: 参考:sleep.yield.wait.join的区别(阿里面试) 我们可能经常会用到 Thread.Sleep 函数来使线程挂起一段时间.那么你有没有正确 ...

  5. Mac & how to uninstall LANDesk

    Mac & how to uninstall LANDesk http://eddiejackson.net/wp/?p=9036 https://community.ivanti.com/d ...

  6. mysql(五)查询缓存

    mysql的逻辑架构图如下: 当开启查询缓存时,mysql会将查询结果缓存到查询缓存区域,结果对应的key是使用查询语句,数据库名称,客户端协议的版本等因素算出的一个hash值. 在下次查询时,根据一 ...

  7. DIH增量、定时导入并检索数据--转载

    原文地址:http://www.ifunit.com/984/solr%E5%AD%A6%E4%B9%A0%EF%BC%88%E4%BA%94%EF%BC%89dih%E5%A2%9E%E9%87%8 ...

  8. 洛谷P1352 没有上司的舞会——树形DP

    第一次自己写树形DP的题,发个博客纪念`- 题目来源:P1352 没有上司的舞会 题目描述 某大学有N个职员,编号为1~N.他们之间有从属关系,也就是说他们的关系就像一棵以校长为根的树,父结点就是子结 ...

  9. [BZOJ2432][Noi2011]兔农 矩阵乘法+exgcd

    2432: [Noi2011]兔农 Time Limit: 10 Sec  Memory Limit: 256 MB Description 农夫栋栋近年收入不景气,正在他发愁如何能多赚点钱时,他听到 ...

  10. 【JQuery】遍历

    一.前言        接着上一章的内容,继续本章的学习. 二.内容 .add 将元素添加到匹配元素的集合中 .add(object) .add(selector,context) .addSelf ...