请列举四种「等比例自适应矩形」实现方案?

引言

本文是由一次面试引发的探讨, 在一次面试过程中被问起「如何实现一个自适应等比例矩形?」, 对于实现方案我依稀记得是有看到过的, 但是一时也想不起来, 所以在面试的时候自然就没有回答出来!!!

面试结束回来也简单 google 了下, 找到实现方案其实基本都大差不差, 无非就是通过 vw 或者 padding 来实现, 所以也就没有怎么总结输出, 直到后面我找到了另外两种方案, 所以就有了这篇文章!!!

下面开始进入主题...

一、相对长度单位「vw」

vw: CSS 中的一个相对长度单位, 1vw 等于视口宽度的 1%

第一个方法, 就是使用 vw 来实现, 这个比较好理解, 当宽度、高度都基于同一个参考标准的一个相对长度, 那么自然就能够实现等比例矩形了

css 复制代码
.box {
  width: 50vw; 
  height: 25vw;
}

这里有个比较大的缺点就是, 宽度、长度只能相对于视口进行自适应; 无法相对于父元素进行自适应

二、使用「padding」属性

第二个方案, 也是早期比较推荐的一种做法; 该方法主要依据是: CSS 在默认情况下 marginpadding 属性的 垂直方向百分比值 都是 相对于父元素的宽度 来计算的

有代码如下: .container 宽度设置为 500px, .container::before 通过 padding-top: 50%; 把父元素撑开, 实现 2:1 的矩形

html 复制代码
<style>
  .container {
    width: 500px;
    background-color: #91caff;
  }

  .container::before {
    content: '';
    display: block;
    padding-top: 50%; /* 相对于父元素宽度 */
  }
</style>
<div class="container"></div>

最后效果如下:

该方法兼容性是没有问题的, 但是由于容器被子元素占满, 我们如果想要在容器内部放置其他内容, 就需要多一层嵌套 div, 然后通过 position 来布局, 如下代码所示: 新增 .content 元素, 然后通过 position 进行定位

html 复制代码
<style>
  .container {
    width: 500px;
    position: relative;
    background-color: #91caff;
  }

  .container::before {
    content: '';
    display: block;
    padding-top: 50%; /* 相对于父元素宽度 */
  }

  .content {
    inset: 0;
    position: absolute;
  }
</style>
<div class="container">
  <div class="content">
    content
  </div>
</div>

最后效果如下:

补充: 你是否好奇, 为啥 marginpadding 在垂直方向上的百分百是相对父元素宽度的, 而不是高度呢? 我们都知道父元素的高度往往由子元素来决定, 试想下如果 marginpadding 垂直方向的百分百比是相对于父元素高度的, 那么当它们设置了一个百分比, 相应的, 父元素高度会进行适应性增加; 此时父元素高度增加的同时, marginpadding 若以父元素高度为基准, 则其实际数值又会发生适应性变化, 双向因果会造成循环, 所以 W3C 的规范做出了以上规定

三、使用「aspect-ratio」属性

CSS 属性 aspect-ratio 可以为盒子设置一个首选的宽高比例, 这个宽高比可以用于计算 auto 尺寸以及其他布局函数

第三个方案是通过 aspect-ratio 来实现, aspect-ratio 属性可以为元素设置 宽度和高度 的一个 默认比例, 这样的话我们就很容易实现一个任意比例的矩形了, 如下代码: 通过 aspect-ratio: 2 / 1; 约定默认情况下容器的宽度和高度比例为 2:1, 由于容器只设置了宽度, 那么在 aspect-ratio 的约束下, 高度将自适应性, 从而实现了一个 2:1 的等比例矩形

html 复制代码
<style>
  .container {
    width: 500px;
    aspect-ratio: 2 / 1;
    background-color: #91caff;
  }

</style>
<div class="container"></div>

最后效果如下:

3.1 关于「aspect-ratio」更多补充

  1. 兼容性: 到目前(2023.10)为止除了 IE, 其他浏览器基本都已支持
  1. 当容器内容足够多的情况下 aspect-ratio 的限制将失效, 如下代码所示: 为 .container 容器添加一段文本, 设置容器宽度为 200px, 设置 aspect-ratio 也就是默认容器宽高比为 2:1
html 复制代码
<style>
  .container {
    width: 200px;
    aspect-ratio: 2 / 1;
    background-color: #91caff;
  }

</style>
<div class="container">
  男子吊环决赛中, 东京奥运会冠亚军刘洋、尤浩为中国队上了 "双保险", 最终以15.233分和14.833分分别摘得金牌和铜牌
</div>

最终效果如下: 由于容器内容很多, 最终会发现容器的宽度为 200, 高度为 110aspect-ratio 设置的比例并不匹配

那么这是为什么呢? 主要原因是 aspect-ratio 对容器尺寸的影响其实是最低的, 我们都知道影响容器尺寸的属性有很多包括min-width/min-heightmax-width/max-heightwidth/height容器本身内容aspect-ratio, 那么它们对容器尺寸的影响优先级如下 min-* > max-* > width/height > 内容 > aspect-ratio, 也就是容器本身内容对容器尺寸的影响力大于 aspect-ratio 所以就出现了上面 👆🏻 这个现象

这里解决办法其实也简单, 我们只需要为容器设置一个 min-height: 0; 即可:

diff 复制代码
<style>
  .container {
    width: 200px;
    aspect-ratio: 2 / 1;
    background-color: #91caff;
+   min-height: 0;
  }

</style>
<div class="container">
  男子吊环决赛中, 东京奥运会冠亚军刘洋、尤浩为中国队上了 "双保险", 最终以15.233分和14.833分分别摘得金牌和铜牌
</div>

最终效果如下: 从尺寸上来看 aspect-ratio 成功生效了, 至于文本溢出, 可以设置 overflow: auto; 来解决

  1. width/heightmin/max-width/height 的相互影响:
  • width/height 属性的关系:

    • widthheight 都设置了, 那么就没 aspect-ratio 任何事咯
    • widthheight 都没设置, 那么宽度自适应, 高度则按照 aspect-ratio 以及容器的宽度来计算高度
    • widthheight 设置其一, 则另一个尺寸按 aspect-ratio 来计算
  • min/max-width/height 属性的关系:

    • 实际上是 aspect-ratiowidth/height 属性关系的延伸
    • 如果设置了 min-width 或者 max-width, 并且影响到容器宽度(可以理解为设置固定的 width)
    • 如果设置了 min-height 或者 max-height, 并且影响到容器高度(可以理解为设置固定的 height)
    • 那么最后的关系还是和上文的 width/height 是一致;

个人理解: width/height 也好 min/max-width/height 也罢, 只要容器宽度和高度都被影响到(受限), 那么 aspect-ratio 将失效; 如果其中一个被影响到(受限), 那么 aspect-ratio 将按照 容器最终的尺寸 计算另一个尺寸的大小; 如果容器的宽度高度都没受到影响, 那么 aspect-ratio 将默认按照 容器的最终宽度 来计算另一个尺寸的大小

四、使用「cqw」单位

第四种, 也是文本介绍的最后一种方法!! 这里其实是使用了 CSS 容器查询的新特性, 容器查询 可以实时获取到指定容器元素的一个尺寸, 并通过媒体查询来监听容器尺寸的变化, 来做一些自适应!!! 当然本文并不需要使用到媒体查询, 但我们可以借用配套的 CSS 单位 cqw 来实现等比例矩形

我们来直接看代码, 基于代码来对 cqw 进行简单讲解, 如下代码:

  • container-type: inline-size; 定义了一个可查询容器, 个人理解就是将容器标记为可查询容器
  • cqwCSS 单位中的一种, 1cwq 它等于 最近可查询祖先容器 宽度的 1%
html 复制代码
<style>
  .container {
    width: 200px;
    container-type: inline-size;
    background-color: #91caff;
  }

  .content {
    height: 50cqw; /* 最近可查询容器宽度的 50% */
  }

</style>
<div class="container">
  <div class="content"></div>
</div>

最后效果如下:

通过 cqw 可以很容器实现任意比例的矩形, 但是它有个缺点就是您可能需要额外嵌套一层!!!

补充: 更多容器查询长度单位

  • cqw: 查询容器宽度的 1%
  • cqh: 查询容器高度的 1%
  • cqi: 查询容器行向尺寸的 1%
  • cqb: 查询容器块尺寸的 1%
  • cqmin: cqicqb 中较小的值
  • cqmax: cqicqb 中较大的值

五、参考

相关推荐
Martin -Tang35 分钟前
vite和webpack的区别
前端·webpack·node.js·vite
迷途小码农零零发36 分钟前
解锁微前端的优秀库
前端
王解1 小时前
webpack loader全解析,从入门到精通(10)
前端·webpack·node.js
老码沉思录1 小时前
写给初学者的React Native 全栈开发实战班
javascript·react native·react.js
我不当帕鲁谁当帕鲁2 小时前
arcgis for js实现FeatureLayer图层弹窗展示所有field字段
前端·javascript·arcgis
那一抹阳光多灿烂2 小时前
工程化实战内功修炼测试题
前端·javascript
放逐者-保持本心,方可放逐3 小时前
微信小程序=》基础=》常见问题=》性能总结
前端·微信小程序·小程序·前端框架
毋若成5 小时前
前端三大组件之CSS,三大选择器,游戏网页仿写
前端·css
红中马喽5 小时前
JS学习日记(webAPI—DOM)
开发语言·前端·javascript·笔记·vscode·学习
Black蜡笔小新6 小时前
网页直播/点播播放器EasyPlayer.js播放器OffscreenCanvas这个特性是否需要特殊的环境和硬件支持
前端·javascript·html