margin/padding百分比值的计算

时间:2021-10-27 00:30:01

1、百分比介绍

一般元素的宽度用百分比值表示时,元素的总宽度包括外边距取决于父元素的width,这样可能得到“流式”页面,即元素的外边距会扩大或缩小以适应父元素的实际大小。如果对这个文档设置该样式,使其子元素使用百分数外边距,当用户修改浏览窗口的宽度时,外边距会随之扩大或缩小。

margin-right/margin-left的百分比值是相对于父元素的宽度来计算的,这很好理解;而margin-top/margin-bottom为什么也是以父元素的width为参照物的呢?

2、为什么呢?

CSS权威指南中的解释:若是相对于父元素的高度计算会形成死循环。
“我们认为,正常流中的大多数元素都会足够高以包含其后代元素(包括外边距),如果一个元素的上下外边距是父元素的height的百分数,就可能导致一个无限循环,父元素的height会增加,以适应后代元素上下外边距的增加,而相应的,上下外边距因为父元素height的增加也会增加,形成无限循环。”

还有一种说法是根本原因并不是因为死循环。例如zhangxinxu认为相对于 height 计算,大多数情况下计算值都是 0,跟摆设没什么 区别,还不如相对宽度计算,因为 CSS 默认的是水平流,计算值一直会有效,而且我们还可以 利用这一特性实现一些有意思的布局效果。也就是面向场景和需求设计,这种设计可以让我们轻松实现自适应的等比例矩形效果。

Anyway,总而言之就是:

默认的水平文档流方向下,CSS margin和padding属性的垂直方向的百分比值都是相对于父元素宽度计算的。

3、小栗子

<div style="width:100px; border: 1px solid gray;"  id="box">
<div id="container">1</div>
</div> #container{
padding-top: 50%; // margin-top: 50%;
background-color: pink;
}

div中没有内容时,实现的是一个宽高为1:2的小矩形。padding-top: 50%;表示元素的高度为宽度的一半。padding-top: 100%; 可实现宽高为1:1的小矩形。(改为padding: 50%`,实现的是一个宽高1:1的小矩形,因为50%+50%=100%;)

从盒子模型可以看出,虽然容器的内容高度为0,但由于有了跟内容宽度一致的padding,因此整体视觉效果上像是被撑开了。

使用方法: padding-top用来设置元素的宽高比例;该元素在父元素宽度变化的过程中将保持自身固定的宽高比。

4、应用

对于绝大多数都布局,我们并不要求非要比例固定,但是有一种情况例外,那就是图片,因为图片原始尺寸它是固定的。在传统的固定宽度的布局下,我们会通过给图片设定具体的宽度和高度值,来保证我们的图片占据区域稳固;但是在移动端或者在响应式开发情况下,图片最终展现的宽度很可能是不确定的。

此时需要的不是对图片进行固定尺寸设定,而是比例设定。为了维持图片的宽高比固定,即保持原来的尺寸比不变,要做到元素高度随着元素的进行自适应变化。

对于复杂布局,如果图片的宽度是不固定的自适应的,我们通常会想到这么一个取巧的做法,就是只设定图片的宽度例如img { width: 100%; },图片的高度不进行限定,由图片的内容去撑开,这样会出现图片占据的高度有一个从0到计算高度的图片变化,视觉上会有明显的元素跳动,代码层面会有布局重计算。即使图片加载速度很快,容器在图片加载前后都会有一个变型的过程,也就是俗称的“闪烁”,而如果图片加载不出来,整体布局就更是难看了。

所以对图片高宽都进行限定还是有必要的,但是同时要保证宽度自适应。

给子元素/伪元素设置margin/padding撑开容器

由于添加子元素与HTML语义化相悖,因此更推荐使用伪元素(:after)来实现此方案。

<div style="width:100px; border: 1px solid gray;overflow:hidden;">
<div id="container" class="placeholder"></div>
</div> #container {
position: relative;
background-color: pink;
overflow: hidden; // 当使用margin-top需要触发BFC消除与其他元素可能发生margin折叠的问题
}
.placeholder:after {
content: ' ';
display: block;
margin-top: 100%;
}

容器内部如何添加内容

那么,在撑开容器后,如何给容器添加内容(图片、文本等)呢?
利用position: absolute;

<div id="container" class="placeholder">
<img src="xxx.jpg" />
</div> #container {
position: relative;
background-color: pink;
overflow: hidden;
}
.placeholder:after {
content: ' ';
display: block;
margin-top: 100%;
}
img {
position: absolute;
top: 0;
width: 100%;
}

References

CSS百分比padding实现比例固定图片自适应布局
巧用margin/padding的百分比值实现高度自适应(多用于占位,避免闪烁)