【每日一题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 {
  width60vw;
  height60vw;
}

grid + vw

使用grid设置一行一列,快速实现一个正方形。

grid-template的值可以是任何单位,这里我们继续利用vw相对于视口宽度计算的特点,实现等比例缩放的正方形。

<div class="grid">div>
.grid {
  display: inline-grid;
  grid-template-columns60vw;
  grid-template-rows60vw;
}

推荐一个关于grid的在线游戏学习网站[1]

今天玩了一下,对知识点实现效果的印象还挺深刻的。
因为解说是英文版的,英语能力弱的同学可以先看下API再去学习。

border + vw

我们利用四个方向的border-width,将其都设置为固定的vw值,实现一个正方形。

同理,宽度单位使用vw实现自适应等比缩放。

<div class="border">div>
.border {
  display: inline-block;
  border30vw solid #53a9ff;
}

具体border是怎么拼成正方形的,我搞了个四个方向颜色不同的border组成的彩色正方形。


有没有想到《鱿鱼游戏》里的打面包场景?梦回童年啊有没有!

padding + vw

实现同border,利用的是四个方向的padding将元素撑开。

<div class="padding">div>
.padding {
  display: inline-block;
  padding30vw;
}

设置为inline-block是因为,块元素宽度是视口宽度,而我们的padding只设置了“30/视口宽度”。

padding矩形

根据上边的思路,我们发现当有内容时,其实可以实现一个矩形:

<div class="padding2">div>
.padding2 {
  padding20vw;
}

相对单位的混用

有了上边的方案,我们可以总结出来,主要就是使用相对长度单位。我们不仅可以用vw,也可以用百分比单位实现正方形宽高等比例缩放的效果。

<div class="square">div>
.square {
  width30%;
  height30vw;
}

这里代码处,原理同第一种情况。
不过width这里长度单位是%,原因是默认值的情况下,div作为块元素其宽度就是视口宽度。
所以这种情况下我们宽度设置%也就等于设置了vw

优点:

简洁方便

缺点:

需要注意兼容性问题

padding + %

要知道,margin、padding的百分比数值是相对于父元素的宽度计算的。我们可以利用这个特点,将元素垂直方向的一个 padding 值设定为与 width 相同的百分比来实现一个正方形:

如果width的值再是相对的单位(vw、%等)就可以实现响应式等比例缩放了。

<div class="padding-square">
  内容加了一行,高度设为0
div>
.padding-square {
  width30%;
  padding-bottom30%;
  /* 因为有内容会和padding-bottom共同占据高度,所以高度设置为0 */
  height0;
  /* 这样会导致max-height就失效了 */
  /* max-height: 100px */
}

正如代码里注释的,因为div里有内容,导致 “内容高度 + padding-bottom的值” 算出来的高度会超过容器宽度,这样就形不成正方形了,所以我们再将height手动设置为0。

padding + vw

与上边同理的代码,我们将%换成vw,不用父元素的宽度作为统一参照物,改为用视口的宽度。

.padding-square {
  width30vw;
  padding-bottom30vw;
  height0;
}

哎,我放着%就是不用,哎,我就是玩儿~

优点:

简洁明了,兼容性好

缺点:

会导致在元素设置上的 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 {
  width30%;
  overflow: hidden;
  /* 这样max-height就生效了 */
  /* max-height: 100px */
}
.margin::after {
  content"";
  display: block;
  margin-top100%;
  /* 或者使用 padding-bottom: 100%; */
}

上边代码同理,我们也可以不用百分比,改用vw作为长度单位也行:

.margin {
  width30vw/* 改变宽度值的单位即可 */
}
.margin::after {
  content"";
  display: block;
  margin-top100%;
}

等等……我好像发现了了不起的规律:

margin-top设置100%,就是正方形;设置50%,就是2:1的矩形。

所以div的具体图形宽高比就由margin-top的百分值决定了!所以,我们想实现图片裁剪的功能,遮罩层的尺寸是不是就可以用这个方法计算了!

一个实现2:1矩形的例子:

<div class="margin rect">div>
.margin {
  width30%;
  overflow: hidden;
}
.margin.rect::after {
  content"";
  display: block;
  /* 矩形 */
  margin-top50%;
}



参考资料

[1]

grid游戏学习网站: http://cssgridgarden.com/。


文中示例源代码在“阅读原文”


所有《每日一题》的 知识大纲索引脑图 整理在此:https://www.yuque.com/dfe_evernote/interview/everyday


END
愿你历尽千帆,归来仍是少年。
浏览 117
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报