2

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

 1 year ago
source link: https://blog.p2hp.com/archives/9954
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

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

塞纳猫

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

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

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

CSS 纵横比

如果你这样做:

.aspect-ratio-demo {
  aspect-ratio: 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/


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK