纵横比

Avatar of Geoff Graham
Geoff Graham

DigitalOcean 为您旅程的每个阶段提供云产品。 立即开始使用 $200 免费积分!

CSS 属性 aspect-ratio 允许您创建保持比例尺寸的框,其中框的 高度宽度 自动计算为比率。 这有点数学,但想法是您可以将此属性上的一个值除以另一个值,而计算出的值确保框保持该比例。

换句话说,此属性有助于我们一致地调整元素的大小,因此元素的比例在它增大或缩小的时候保持不变。

.element {
  aspect-ratio: 2 / 1; /* ↔️ is double the ↕️ */
}

.element {
  aspect-ratio: 1 / 1; /* ⏹ a perfect square */
}

aspect-ratioCSS 盒模型规范级别 4 中定义,该规范目前处于工作草案阶段。 这意味着它仍在进行中,有可能会发生变化。 但是,由于 Chrome 和 Firefox 在实验性标志后面支持它,而 Safari Technology Preview 在 2021 年初添加了对它的支持,因此有强烈的迹象表明 aspect-ratio 正在获得很大的动力。

语法

aspect-ratio: auto || <ratio>;

用简单的英语来说:aspect-ratio 默认情况下被认为是 auto,或者接受一个 <ratio> 作为值,其中 <width / height>

  • 初始值:auto
  • 适用于:所有元素,除了内联框和内部 ruby 或表格框
  • 继承:
  • 百分比:n/a
  • 计算值:指定的关键字或一对数字
  • 动画类型:离散

Safari Technology Preview 153 于 2022 年 9 月 7 日发布。 在该版本中,aspect-ratio 的初始值将 auto 替换为 default

/* Keyword values */
aspect-ratio: auto; /* default */

/* Ratio values */
aspect-ratio: 1 / 1; /* width and height are equal proportion */
aspect-ratio: 2 / 1; /* width is twice the height*/
aspect-ratio: 1 / 2; /* width is half the height */
aspect-ratio: 16 / 9  /* typical video aspect ratio */
aspect-ratio: auto 4 / 3; /* width:height, unless it's a replaced element */
aspect-ratio: 0.5; /* float value */

/* Global values */
aspect-ratio: inherit;
aspect-ratio: initial;
aspect-ratio: unset;
  • auto: 默认值,它指定元素没有首选纵横比,应该按正常方式调整自身大小。 因此,替换元素(如具有内在纵横比的图像)会使用  纵横比。
  • <ratio>: 两个正数,用正斜杠 (/) 分隔,周围可以有或没有空格,目标是元素的宽度和高度。 如果只有一个值,则第二个值被认为是 1。 涉及首选纵横比的尺寸计算使用由 box-sizing 指定的框尺寸。
  • initial: 应用属性的默认设置,即 auto
  • inherit: 采用父级的 aspect-ratio 值。
  • unset: 从元素中移除当前纵横比。

它可以接受两个值

此属性可以同时接受两个值,一个是 auto,另一个是 <ratio>

.element {
  aspect-ratio: auto 1 / 1;
}

如果同时指定 auto <ratio>,则首选纵横比是指定宽度除以高度的比率,除非它是具有内在纵横比的替换元素,在这种情况下,将使用该纵横比。

正如您在以下演示中看到的,为 div 和 <img>(替换元素)设置了相同的值,div 元素使用 <ratio> 并变成正方形,但图像遵循其内在纵横比。 如果从值中删除 auto ,您会看到图像被迫变成正方形

它适用于替换和非替换内容

如果您正在想,“嗯,是的,浏览器已经为我们对图像做了这件事?” 答案是:绝对。 浏览器对替换内容(如图像)进行了一些精密的纵横比计算。 因此,如果图像的宽度为 500 像素,浏览器会灵活使用其 CSS 布局算法来维护图像的 内在或“自然”尺寸aspect-ratio 属性可以用来有效地覆盖这些自然尺寸。

但是非替换内容没有自然比例。 这是我们使用的大部分内容,比如 div。 aspect-ratio 不是试图保持元素的自然比例,而是设置一个“首选”大小。

目前,规范中指出,旧的 CSS 规范,特别是 CSS 2.1,并没有明确区分替换内容和非替换内容。这意味着我们可能会看到规范中添加了一些额外的特殊情况来帮助澄清它们。目前,我们看到浏览器正在推出对分别为替换内容和非替换内容设置首选纵横比的支持,其中一些早期支持实验性标记的浏览器可能只支持 aspect-ratio 用于非替换内容。随着浏览器支持的发展,绝对值得关注 浏览器支持

它本身就可以工作,无需指定 widthheight

所以,是的,我们可以像这样简单地将其放到一个元素上

.element {
  aspect-ratio: 16 / 9;
}

…元素的默认 width: auto 会隐式地生效,设置元素的尺寸。

在 CodePen 上查看实时演示

widthheight 在同一个元素上时,它会改变

假设我们有一个宽度为 300pxaspect-ratio3/1 的元素。

.element {
  aspect-ratio: 3 / 1;
  width: 300px;
}

本质上,aspect-ratio 想要根据它使用的上下文自行计算元素的尺寸。但有了这个 width,它告诉 aspect-ratio 使用 300px 作为宽度来计算元素的纵横比框。结果,就像我们刚刚写了

.element {
  height: 100px;
  width: 300px;
}

这是有道理的!记住,当没有指定 widthheight 时,浏览器会假设它们是 auto 并以此为基础。当我们提供显式的 widthheight 值时,这些值会被使用。

它在某些情况下会被忽略

这就是事情变得有点让人难以理解的地方,因为在某些情况下,aspect-ratio 被忽略了,或者它的计算结果受到其他属性的影响。这包括

widthheight 都在元素上声明时

我们刚刚看到了如何在元素上声明 width height 会影响 aspect-ratio 的计算。但如果元素已经同时拥有 widthheight,那么这两个值会被使用,而不是 aspect-ratio。它需要这两个属性来覆盖 aspect-ratio;单独设置 height width 不会破坏元素的纵横比。

widthheight 都在同一个元素上设置时,aspect-ratio 会被忽略。

有道理,对吧?如果使用 widthheight 中的任何一个都会强制 aspect-ratio 在计算中使用该值,那么逻辑上使用这两个值会完全覆盖 aspect-ratio,因为这两个值都已经提供并设置了。

当内容超出比例时

简单地说,如果你有一个具有纵横比的元素,并且内容太长以至于迫使元素扩展,那么元素就会扩展。如果元素扩展了,它的尺寸就会改变,因此不再有纵横比。这就是为什么规范说该属性设置了“首选”纵横比。它是首选的,但不是规定的。

不喜欢这种工作方式?在元素上设置 min-height: 0; 将允许内容溢出首选纵横比,而不是扩展它。

在 CodePen 上查看实时演示

当它“输给” min-*max-* 属性时

我们刚刚看到了它是如何工作的,对吧?当内容超出盒子尺寸时,aspect-ratio 实际上消失了,因为盒子会随着内容一起扩展。我们可以用 min-width: 0 来覆盖它。

这是因为所有的 min-*max-* 属性通常与 widthheight 在盒子模型计算的统治权争夺战中展开竞争。例如

.element {
  min-width: 500px; /* 🏆 Winner! */
  width: 100px;
}

但是

.element {
  min-width: 500px;
  width: 700px; /* 🏆 Winner! */
}

这是因为 min-width 正在阻止 width 低于特定值,或者它被忽略了,因为 width 已经将元素设置为超过它需要的最小宽度。min-heightmax-widthmax-height 也是如此。

所有这些的重点是:如果我们设置了与 aspect-ratio 在同一个元素上的 min-*max-* 属性,并且它们“赢”过了 widthheight,那么它们将覆盖 aspect-ratio。我告诉过你,它有点让人难以理解。🤯

用例

替换元素,比如图片或视频,本身就具有固有的长宽比,因此当它们放大或缩小时,它们会保持其长宽比,但非替换元素却没有这种便利,有时您需要为它们提供这种行为。

以下是一些 `aspect-ratio` 变得实用的示例。

响应式 iframe

一个非常常见的用例是,您想嵌入一个 iframe 来显示来自另一个网站(如 YouTube)的视频。在这种情况下,如果您将宽度设置为 100%,并且您设置了高度,视频将会变形。

为了获得一个保持其长宽比的响应式 iframe,您可以按照以下步骤操作。

iframe {
  aspect-ratio: 16 / 9;
  width: 100%;
  height: auto;
}

如果 iframe 设置了 width 和 height 属性,如下所示

<iframe src="https://example.com" width="800" height="600"></iframe>

…那么您可以自动设置 `aspect-ratio` 如下所示

iframe[width][height] {
  aspect-ratio: attr(width) / attr(height);
}

英雄图片

将 `background-image` 设置为元素不会对该元素的大小有任何影响。因此,要创建英雄图片,如果图片在背景中,您需要在元素上设置一个高度,而固定高度并不是非常响应式!

在这里,您可以使用 `aspect-ratio` 属性来创建一个保持其 `background-image` 长宽比的英雄元素。

.hero {
  aspect-ratio: 4 / 3;
  background: url(background.png);
}
网格布局的一致性

想象一下,在一个带有自动填充机制的 flexbox 或网格布局中,您可能希望项目保持正方形,但项目宽度和高度可以根据其内容或父元素的大小缩小或放大,因此项目很可能不会保持正方形。

将 `aspect-ratio` 设置为 `1 / 1` 会在您的项目宽度缩放时动态更改高度。

.grid-container {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
}

.grid-item {
  aspect-ratio: 1 / 1;
}

在下面的图片库中,由于图片具有随机大小,因此使用 `aspect-ratio` 属性来保持其高度一致。删除项目列表中的 `aspect-ratio` 属性,看看效果。

此外,通过使用 object-fit,您可以将图片拟合到正确的尺寸。

浏览器支持

有关主要浏览器对 mdn-css__properties__aspect-ratio 特性的支持数据

处理遗留浏览器支持

在拥有此属性之前,处理此问题的一种方法是 填充框技术,现在由于 CSS @supports,我们可以使用该技术来支持较旧的浏览器。

在下面的示例中,使用伪元素策略来为较旧浏览器添加 `aspect-ratio` 属性的回退。

.element {
  aspect-ratio: 1 / 1;
}

@supports not (aspect-ratio: 1 / 1) {
  .element::before {
    float: left;
    padding-top: 100%;
    content: "";
  }

  .element::after {
    display: block;
    content: "";
    clear: both;
  }
}

更多信息