默认情况下,an<img>占用零空间,直到浏览器加载足够的图像以知道其尺寸:

一只黑猫,看着镜头,在他的背上滚动
塞纳猫

运行演示时,您会<figcaption>立即看到。然后,几秒钟后,这一段和随后的页面内容向下移动,为图像腾出空间。这使得用户体验非常令人沮丧,因为内容从用户的眼睛/手指/指针下方移出。

十多年来,我们不得不使用愚蠢的技巧来手动应用纵横比,然后,典型的,两个更好的解决方案几乎同时出现。它们是 CSSaspect-ratiowidth&height表示性提示。

那么,您应该使用哪个?首先,让我们看看这些功能是如何工作的,因为那里有很多错误信息……

CSS 纵横比

如果你这样做:

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

......你得到这个:

16 / 9

该功能于 2021 年末登陆 Safari 15 后,便成为跨浏览器兼容,并于当年早些时候登陆 Chrome 和 Firefox。

它适用于任何元素,但这里有一个演示<img>

img {
  aspect-ratio: 16 / 9;
  width: 100%;
}
一只黑猫,看着镜头,在他的背上滚动
塞纳猫

这一次,图像一出现在文档中就为其内容保留空间,因此一旦加载,内容就不会移动。

另一个解决方案是……

宽度和高度表示提示

如果您在图像上设置尺寸:

<img width="1598" height="899" src="" alt="" />

并将高度设置为auto

img {
  height: auto;
}

…即使在加载之前,图像也会应用纵横比。

一只黑猫,看着镜头,在他的背上滚动
塞纳猫

它于 2019 年登陆 Chrome 和 Firefox,并在一年后登陆 Safari 14 时成为跨浏览器兼容。所以,这个特性的存在时间比 CSS 长一点aspect-ratio

此外<img>,此功能还适用于<video><input type="image">

更新:<video>尽管浏览器根据规范实现了该功能,但规范已损坏,因此在实践中不起作用。

然而,有一些错误的信息在流传……

不,这不使用attr()

很多文章都说这个特性是通过这样的用户代理样式表工作的:

这不是它的实际工作方式

img,
input[type='image'],
video,
embed,
iframe,
marquee,
object,
table {
  aspect-ratio: attr(width) / attr(height);
}

首先,此功能不适用于embediframemarqueeobjecttable。但是,这种用法attr()在实践中也行不通,因为它返回一个字符串。为了使其正常工作,您需要将属性转换为 CSS 支持的数字!

这也不是它的工作方式

img,
input[type='image'],
video {
  aspect-ratio: attr(width number) / attr(height number);
}

但这不是它的工作原理,因为:

没有浏览器支持所有属性的 attr
在caniuse.com上支持 attr()

…没有浏览器支持attr(),除了非常特殊的情况,比如content伪元素。希望有一天会改变!

它实际上是如何工作的?

这是规范必须说的:

widthheight属性映射到和元素上的纵横比属性(使用维度规则) ,以及具有图像按钮状态的属性的元素。imgvideoinputtype

嵌入内容和图像的属性 - HTML

因此,它确实映射到该aspect-ratio属性。具体来说:

…用户代理应该使用解析的维度作为表单的“纵横比”属性的表示提示auto w / h

映射到纵横比 - HTML

您可以将“表示性提示”视为有点像内部应用的零特异性内联样式。

这使用了aspect-ratio我之前没有提到的一个特性:

.aspect-ratio-demo {
  aspect-ratio: auto 16 / 9;
}

新位是auto. 这是规范所说的:

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

— CSS 大小调整级别 4

很多文章都掩盖了这一点,可能是因为规范文本有点难以阅读,但它增加了一些重要的行为:

An<img>是一个“替换元素”,但在浏览器加载足够多的图像以知道其真实宽度和高度之前,它没有“自然纵横比”。这意味着16 / 9一旦浏览器从图像中获得真实数据,该位就会被忽略。这通常无关紧要,因为结果是相同的。但是,假设我的宽度和高度错误:

<img width="4" height="3" src="" alt="" />

浏览器将使用 的表示性提示aspect-ratio: auto 4 / 3,但图像实际上是16 / 9。这是发生的事情:

一只黑猫,看着镜头,在他的背上滚动
塞纳猫

当图像添加到页面时,它会占用4 / 3我指定的区域。但是一旦加载,auto规则就会生效,并且浏览器会将纵横比更正为16 / 9.

将此与以下行为进行比较:

img {
  aspect-ratio: 4 / 3;
  width: 100%;
}
一只黑猫,看着镜头,在他的背上滚动
塞纳猫

如果没有auto,则<img>剩余4 / 3,并且图像会显得拉伸。您可以通过以下方式避免拉伸object-fit

img {
  aspect-ratio: 4 / 3;
  width: 100%;
  object-fit: cover;
}
一只黑猫,看着镜头,在他的背上滚动
塞纳猫

在这种情况下,图像的某些部分被裁剪。哦,还有一件事:

Firefox 中的一个小问题

响应式图像可让您提供不同的图像以在不同的宽度下使用:

<picture>
  <source
    width="1000"
    height="614"
    media="(max-width: 800px)"
    srcset="wide-view.jpg"
  />
  <img width="800" height="547" src="zoomed-in.jpg" alt="" />
</picture>

在这种情况下,两个图像具有不同的纵横比。Chrome 和 Safari 使用正确的widthheight取决于使用的源,但 Firefox 将始终使用<img>.

F1 赛车在砾石中
罗曼·格罗斯让(Romain Grosjean)在拐角处开着很长的路

这是跟踪此问题的 Firefox 错误。希望它会很快得到修复!

那么,我们应该使用哪种方法呢?

好的,到目前为止,这篇文章一直是一个巨大的支线任务。现在我们到了实际点。而且,在我看来,答案是……没什么新鲜的。

我们有一个解决方案,aspect-ratio它是基于 CSS 的。另一个解决方案是表示性提示,它使用widthheight属性。这个问题非常类似于“这个图像应该是 a<img>还是 CSS background-image?” 答案是一样的:是内容还是设计?

如果我在博客上的文章中添加图片,那就是内容。我希望保留空间是内容的纵横比。如果我弄错了widthandheight属性,我宁愿从内容图像中使用正确的值。因此,widthheight属性感觉最合适。这意味着我可以只创作内容,而不需要深入研究内联样式。

如果设计要求图像的布局是特定的纵横比,那么aspect-ratio在 CSS 中强制执行可能是合适的。例如,必须是一个英雄形象16 / 9——如果形象不完全16 / 9,我不希望它弄乱我的设计,我希望设计优先。虽然,如果图像实际上不是那个纵横比,它最终会被拉伸 ( object-fit: fill)、信框 ( object-fit: contain) 或裁剪 ( object-fit: cover)。没有一个是理想的。

您可以使用aspect-ratio和媒体查询来弥补 Firefox 在<picture>艺术指导方面缺乏支持。但是,我希望他们能尽快修复这个错误,所以我们不需要破解它。

就是这样!我们花了十年的时间才真正解决了这个问题,但现在你可以使用widthheight属性来避免布局转换,或者aspect-ratio在 CSS 中,以最合适的为准。

 

来自 https://jakearchibald.com/2022/img-aspect-ratio/

如何保持网页图像的纵横比:aspect-ratio vs width & height 属性
标签: