前言
最近做项目的时候遇到一个场景,需要在一个宽度未定的容器下面摆放三张方形的图片。我们都知道,如果需要图片显示为正方形的话,一般需要已知确定的宽高数值,然后去限定图片包裹块的大小,然后设置图片宽高100%去撑满这个图片包裹块。但是在这个场景下,未知宽度的容器,就代表了我们不知道图片需要展示的确切宽度数值,只知道它相对于父容器应该是1/3的宽度比例,那么这就代表我们无法给予图片包裹块高度等同于宽度的确切数值去让图片变成方形的。
<!DOCTYPE html>
<html lang="en">
<head>
<title>Document</title>
<style>
/* 未知宽度容器 */
.container {
display: flex;
width: 100%;
background-color: #ccc;
}
.img-wrapper {
width: 33%;
/* 这里无法设置与宽度大小相同的值的高度 */
}
.img-wrapper img {
height: 100%;
width: 100%;
object-fit: cover;
}
</style>
</head>
<body>
<div class="container">
<div class="img-wrapper">
<img src="./demo.png" alt="demo">
</div>
<div class="img-wrapper">
<img src="./demo.png" alt="demo">
</div>
<div class="img-wrapper">
<img src="./demo.png" alt="demo">
</div>
</div>
</body>
</html>
在高度中拿到宽度
这个场景的难点在于,宽度不是固定的像素,是未知的,但是我们又需要在高度上设置和宽度相同的值才能使得图片变成方形;也就是说我们需要在高度上拿到CSS自己随时算出来的宽度值。
这个时候我想到一个很少使用的情况——margin/padding的百分比值。
我想大多数时候,大家使用margin/padding的时候,都是设置固定的像素值而非使用百分比的值,我们都知道在CSS中百分比值都是一个相对的值(比如width:100%是取父元素的宽度的100%),那么margin/padding的百分比值是取什么的相对值呢?没错,就是取的父元素的宽度值。
可能有人会有疑问,啊,你说padding/margin left/right这种横向的值取宽度的相对值还有的说,为什么纵向的margin/padding top/bottom是取宽度的相对值而不是取高度的相对值呢?
这个其实在CSS权威指南中有说明,如果取高度的相对值,可能会引起死循环:
我们认为,正常流中的大多数元素都会足够高以包含其后代元素(包括外边距),如果一个元素的上下外边距是父元素的height的百分数,就可能导致一个无限循环,父元素的height会增加,以适应后代元素上下外边距的增加,而相应的,上下外边距因为父元素height的增加也会增加,形成无限循环。
利用这个我们就可以在高度上拿到和宽度一样的值了。
绝对定位元素的百分比高度
这个时候,我们已经可以利用margin/padding top/bottom来获取相同的宽度值了,但是,此时图片包裹块的大小应该是 1/3的父元素宽度,然后自己有个高度,在加上我们设置的 margin/padding top/bottom(值为1/3的父元素宽度,也就是等于现在自己的宽度)。很明显,我们要让他变成正方形,只需要将高度设置为0即可。
.img-wrapper {
width: 33%;
padding-bottom: 33%;
height: 0;
}
至于为什么这里使用padding而不使用margin,马上你就知道了,至于是bottom还是top,这个影响不大。
好,此时图片的包裹块已经是完美的正方形,但是这里出现一个问题,包裹块的高度设置为0之后,内容块的高度就为0了,图片撑满包裹块的height:100%是相对父元素内容块的高度,此时也就为0了,图片就显示不出来了。
那么现在应该想办法让图片元素height:100%取到包裹块的内容块+内边距的高度,这个时候绝对定位元素的特性就起作用了。
当元素绝对定位的时候,height百分比值是相对于离他最近的具有定位特性(position不是static)的祖先元素的padding box进行计算,也就是计算的时候还需要将padding值加进来一起计算,而不是只计算内容块的值。
利用这个特性,我们将代码做出如下修改:
.img-wrapper {
position: relative;
width: 33%;
padding-bottom: 33%;
height: 0;
}
.img-wrapper img {
position: absolute;
height: 100%;
width: 100%;
object-fit: cover;
}
然后我们就可以看到图片如你想的一样变成正方形了,完美!这里也就说明了我们上面为什么不使用margin而使用padding将包裹块撑开成正方形了。至于是选择使用padding-bottom还是padding-top,只是包裹块的内容块位置不同而已,如果使用padding-top的话,需要在img中添加top:0重新定位一下。
最后
利用这个场景,我知道了padding/margin设置百分比值的特殊性和实际的应用场景,而且还了解到绝对定位元素和普通元素计算height百分比值的不同,可以算是收获满满了。这篇文章作为我学习的笔记的同时也希望能帮到你理解更多的CSS特性。我是Godlanbo,我们下篇文章见。