CSS aspect-ratio 属性

CSS 属性,可帮助在自适应布局中保持间距。

纵横比

浏览器支持

  • Chrome: 88.
  • Edge: 88.
  • Firefox: 89.
  • Safari: 15.

来源

纵横比最常见的表示形式是两个整数和一个冒号,表示尺寸:宽度:高度,或 x:y。摄影中最常见的纵横比是 4:3 和 3:2,而视频和更新的消费级相机往往具有 16:9 的纵横比。

Two images with the same aspect ratio. One is 634 x 951px while the other is 200 x 300px. Both have a 2:3 aspect ratio.
两个纵横比相同的图像。一张为 634 x 951 像素,另一张为 200 x 300 像素。两者的纵横比均为 2:3。

随着自适应设计的出现,保持纵横比对于 Web 开发者来说变得越来越重要,尤其是在图像尺寸不同且元素大小根据可用空间变化的情况下。

以下是一些保持纵横比变得重要的示例

  • 创建自适应 iframe,使其宽度为父容器的 100%,而高度应保持特定的视口比率
  • 为图像、视频和嵌入创建固有的占位符容器,以防止在项目加载并占用空间时重新布局
  • 为交互式数据可视化或 SVG 动画创建统一的自适应空间
  • 为多元素组件(例如卡片或日历日期)创建统一的自适应空间
  • 为尺寸各异的多个图像创建统一的自适应空间(可以与 object-fit 结合使用)

Object-fit

定义纵横比有助于我们在自适应上下文中调整媒体大小。此工具箱中的另一个工具是 object-fit 属性,它使用户能够描述块内的对象(例如图像)应如何填充该块

Object-fit demo visualization
展示各种 object-fit 值。请参阅 Codepen 上的演示

initialfill 值会重新调整图像以填充空间。在我们的示例中,这会导致图像被挤压和模糊,因为它会重新调整像素。不太理想。object-fit: cover 使用图像的最小尺寸来填充空间,并根据此尺寸裁剪图像以使其适合空间。它在其最低边界“放大”。object-fit: contain 确保始终显示整个图像,因此与 cover 相反,它采用最大边界的大小(在我们的示例中,这是宽度),并调整图像大小以保持其固有的纵横比,同时使其适合空间。object-fit: none 案例显示图像以其自然大小在其中心(默认对象位置)裁剪。

object-fit: cover 往往在大多数情况下都有效,以确保在处理尺寸各异的图像时获得美观统一的界面,但是,您会丢失信息(图像在其最长边缘被裁剪)。

如果这些细节很重要(例如,在处理美容产品的平面布置图时),则裁剪重要内容是不可接受的。因此,理想的情况是使用各种尺寸的自适应图像,使其适合 UI 空间而不进行裁剪。

旧技巧:使用 padding-top 保持纵横比

Using padding-top to set a 1:1 aspect ratio on post preview images within a carousel.
在轮播中对帖子预览图像使用 padding-top 设置 1:1 的纵横比。

为了使这些更具自适应性,我们可以使用纵横比。这使我们可以设置特定的比例大小,并将媒体的其余部分基于单个轴(高度或宽度)。

当前广泛接受的基于图像宽度保持纵横比的跨浏览器解决方案被称为“Padding-Top Hack”。此解决方案需要父容器和绝对定位的子容器。然后,人们将纵横比计算为百分比,以设置为 padding-top。例如

  • 1:1 纵横比 = 1 / 1 = 1 = padding-top: 100%
  • 4:3 纵横比 = 3 / 4 = 0.75 = padding-top: 75%
  • 3:2 纵横比 = 2 / 3 = 0.66666 = padding-top: 66.67%
  • 16:9 纵横比 = 9 / 16 = 0.5625 = padding-top: 56.25%

现在我们已经确定了纵横比值,我们可以将其应用于我们的父容器。考虑以下示例

<div class="container">
  <img class="media" src="..." alt="...">
</div>

然后我们可以编写以下 CSS

.container {
  position: relative;
  width: 100%;
  padding-top: 56.25%; /* 16:9 Aspect Ratio */
}

.media {
  position: absolute;
  top: 0;
}

使用 aspect-ratio 保持纵横比

Using aspect-ratio to set a 1:1 aspect ratio on post preview images within a carousel.
在轮播中对帖子预览图像使用 aspect-ratio 设置 1:1 的纵横比。

不幸的是,计算这些 padding-top 值不是很直观,并且需要一些额外的开销和定位。使用新的固有 aspect-ratio CSS 属性,用于保持纵横比的语言更加清晰。

使用相同的标记,我们可以将:padding-top: 56.25% 替换为 aspect-ratio: 16 / 9,将 aspect-ratio 设置为指定的 width / height 比率。

使用 padding-top
.container {
  width: 100%;
  padding-top: 56.25%;
}
使用 aspect-ratio
.container {
  width: 100%;
  aspect-ratio: 16 / 9;
}

使用 aspect-ratio 而不是 padding-top 更加清晰,并且不会彻底修改 padding 属性以执行其通常范围之外的操作。

这个新属性还增加了将纵横比设置为 auto 的能力,其中“具有固有纵横比的替换元素使用该纵横比;否则,该框没有首选纵横比。”如果同时指定了 auto<ratio>,则首选纵横比是指定的 width 除以 height 的比率,除非它是具有固有纵横比的 替换元素,在这种情况下,将使用该纵横比。

示例:网格中的一致性

这也非常适用于 CSS 布局机制,如 CSS Grid 和 Flexbox。考虑一个列表,其子项要保持 1:1 的纵横比,例如赞助商图标的网格

<ul class="sponsor-grid">
  <li class="sponsor">
    <img src="..." alt="..."/>
  </li>
  <li class="sponsor">
    <img src="..." alt="..."/>
  </li>
</ul>
.sponsor-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(120px, 1fr));
}

.sponsor img {
  aspect-ratio: 1 / 1;
  width: 100%;
  object-fit: contain;
}
网格中的图像,其父元素具有各种纵横比尺寸。请参阅 Codepen 上的演示。

示例:防止布局偏移

aspect-ratio 的另一个重要功能是它可以创建占位符空间来防止累积布局偏移并提供更好的 Web Vitals。在第一个示例中,从 API(例如 Unsplash)加载资源会在媒体加载完成后创建布局偏移。

在未在加载的资源上设置纵横比时发生的累积布局偏移的视频。此视频是在模拟 3G 网络下录制的。

另一方面,使用 aspect-ratio 会创建一个占位符来防止这种布局偏移

img {
  width: 100%;
  aspect-ratio: 8 / 6;
}
在加载的资源上设置了纵横比的视频。此视频是在模拟 3G 网络下录制的。请参阅 Codepen 上的演示。

奖励提示:用于纵横比的图像属性

设置图像纵横比的另一种方法是通过图像属性。如果您提前知道图像的尺寸,则最佳实践是将这些尺寸设置为其 widthheight

对于上面的示例,如果知道尺寸为 800px x 600px,则图像标记如下所示:<img src="image.jpg" alt="..." width="800" height="600">。如果发送的图像具有相同的纵横比,但不一定具有这些精确的像素值,我们仍然可以使用图像属性值来设置纵横比,并结合 width: 100% 的样式,以便图像占据适当的空间。总而言之,它看起来像这样

<!-- Markup -->
<img src="image.jpg" alt="..." width="8" height="6">
/* CSS */
img {
  width: 100%;
  height: auto;
}

最后,效果与通过 CSS 在图像上设置 aspect-ratio 相同,并且避免了累积布局偏移(请参阅 Codepen 上的演示)。

结论

借助新的 aspect-ratio CSS 属性,该属性已在多个现代浏览器中发布,在您的媒体和布局容器中保持适当的纵横比变得更加直接。

照片由 Amy ShamblenLionel Gustave 通过 Unsplash 提供。