【每日一题NO.65】用CSS实现宽高等比例缩放的方案集合
共 3003字,需浏览 7分钟
·
2021-10-25 04:57
题目:用 纯 CSS 实现 div 宽度自适应,宽高保持等比例缩放
我一共想到了四种实现方案,基本都是基于vw
这个相对单位来实现响应式的。
效果展示:
接下来看下各个方案及其具体实现:
width + height + vw
在昨天的文章中我们提到过vw
这个单位,他是一个相对单位,1vw = 1%的视口宽度
,当视口宽度变化的时候,以vw
为单位的属性其值也会自动重新计算。
我们利用这一点,把div的宽高都设置为固定的vw
值,实现正方形。当视口改变的时候,正方形的宽高也就会等比例缩放。
<div class="vw">div>
.vw {
width: 60vw;
height: 60vw;
}
grid + vw
使用grid
设置一行一列,快速实现一个正方形。
grid-template
的值可以是任何单位,这里我们继续利用vw
相对于视口宽度计算的特点,实现等比例缩放的正方形。
<div class="grid">div>
.grid {
display: inline-grid;
grid-template-columns: 60vw;
grid-template-rows: 60vw;
}
推荐一个关于grid的在线游戏学习网站[1]。
今天玩了一下,对知识点实现效果的印象还挺深刻的。
因为解说是英文版的,英语能力弱的同学可以先看下API再去学习。
border + vw
我们利用四个方向的border-width
,将其都设置为固定的vw
值,实现一个正方形。
同理,宽度单位使用vw
实现自适应等比缩放。
<div class="border">div>
.border {
display: inline-block;
border: 30vw solid #53a9ff;
}
具体border
是怎么拼成正方形的,我搞了个四个方向颜色不同的border
组成的彩色正方形。
有没有想到《鱿鱼游戏》里的打面包场景?梦回童年啊有没有!
padding + vw
实现同border
,利用的是四个方向的padding
将元素撑开。
<div class="padding">div>
.padding {
display: inline-block;
padding: 30vw;
}
设置为inline-block是因为,块元素宽度是视口宽度,而我们的padding只设置了“30/视口宽度”。
padding矩形
根据上边的思路,我们发现当有内容时,其实可以实现一个矩形:
<div class="padding2">div>
.padding2 {
padding: 20vw;
}
相对单位的混用
有了上边的方案,我们可以总结出来,主要就是使用相对长度单位。我们不仅可以用vw
,也可以用百分比单位实现正方形宽高等比例缩放的效果。
<div class="square">div>
.square {
width: 30%;
height: 30vw;
}
这里代码处,原理同第一种情况。
不过width
这里长度单位是%
,原因是默认值的情况下,div作为块元素其宽度就是视口宽度。
所以这种情况下我们宽度设置%
也就等于设置了vw
。
优点:
简洁方便
缺点:
需要注意兼容性问题
padding + %
要知道,margin、padding的百分比数值是相对于父元素的宽度计算的。我们可以利用这个特点,将元素垂直方向的一个 padding
值设定为与 width
相同的百分比来实现一个正方形:
如果width
的值再是相对的单位(vw、%等)就可以实现响应式等比例缩放了。
<div class="padding-square">
内容加了一行,高度设为0
div>
.padding-square {
width: 30%;
padding-bottom: 30%;
/* 因为有内容会和padding-bottom共同占据高度,所以高度设置为0 */
height: 0;
/* 这样会导致max-height就失效了 */
/* max-height: 100px */
}
正如代码里注释的,因为div里有内容,导致 “内容高度 + padding-bottom
的值” 算出来的高度会超过容器宽度,这样就形不成正方形了,所以我们再将height
手动设置为0。
padding + vw
与上边同理的代码,我们将%
换成vw
,不用父元素的宽度作为统一参照物,改为用视口的宽度。
.padding-square {
width: 30vw;
padding-bottom: 30vw;
height: 0;
}
哎,我放着%
就是不用,哎,我就是玩儿~
优点:
简洁明了,兼容性好
缺点:
会导致在元素设置上的 max-height
属性失效
max-height 属性失效的原因是: max-height
属性只限制于 height
,也就是只会对元素的 内容高度(content height) 起作用。
解决的办法是:用一个子元素撑开 content
部分的高度,从而使 max-height
属性生效。如下代码。
伪元素margin + %
首先需要设置伪元素并设定其内容为空,然后margin-top
设置为 100%
。
但需要注意,若使用垂直方向的 margin
撑开父元素,仅仅设置伪元素是不够的,这就涉及到 外边距合并(margin collapse
)的概念,由于容器与伪元素在垂直方向发生了外边距合并,所以父元素高度并没有被撑开。
解决方法是在父元素上触发 BFC
,比如设置overflow:hidden
。
如果伪元素使用padding垂直方向的值来撑开高度,则不需要了。
<div class="margin">div>
.margin {
width: 30%;
overflow: hidden;
/* 这样max-height就生效了 */
/* max-height: 100px */
}
.margin::after {
content: "";
display: block;
margin-top: 100%;
/* 或者使用 padding-bottom: 100%; */
}
上边代码同理,我们也可以不用百分比,改用vw作为长度单位也行:
.margin {
width: 30vw; /* 改变宽度值的单位即可 */
}
.margin::after {
content: "";
display: block;
margin-top: 100%;
}
等等……我好像发现了了不起的规律:
margin-top
设置100%
,就是正方形;设置50%
,就是2:1
的矩形。
所以div的具体图形宽高比就由margin-top
的百分值决定了!所以,我们想实现图片裁剪的功能,遮罩层的尺寸是不是就可以用这个方法计算了!
一个实现2:1
矩形的例子:
<div class="margin rect">div>
.margin {
width: 30%;
overflow: hidden;
}
.margin.rect::after {
content: "";
display: block;
/* 矩形 */
margin-top: 50%;
}
参考资料
grid游戏学习网站: http://cssgridgarden.com/。
文中示例源代码在“阅读原文”
所有《每日一题》的 知识大纲索引脑图 整理在此:https://www.yuque.com/dfe_evernote/interview/everyday