默认情况下,an<img>
占用零空间,直到浏览器加载足够的图像以知道其尺寸:
运行演示时,您会<figcaption>
立即看到。然后,几秒钟后,这一段和随后的页面内容向下移动,为图像腾出空间。这使得用户体验非常令人沮丧,因为内容从用户的眼睛/手指/指针下方移出。
十多年来,我们不得不使用愚蠢的技巧来手动应用纵横比,然后,典型的,两个更好的解决方案几乎同时出现。它们是 CSSaspect-ratio
和width
&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);
}
首先,此功能不适用于embed
、iframe
、marquee
、object
或table
。但是,这种用法attr()
在实践中也行不通,因为它返回一个字符串。为了使其正常工作,您需要将属性转换为 CSS 支持的数字!
这也不是它的工作方式
img,
input[type='image'],
video {
aspect-ratio: attr(width number) / attr(height number);
}
但这不是它的工作原理,因为:
…没有浏览器支持attr()
,除了非常特殊的情况,比如content
伪元素。希望有一天会改变!
它实际上是如何工作的?
这是规范必须说的:
width和
height属性映射到和元素上的纵横比属性(使用维度规则) ,以及具有图像按钮状态的属性的元素。
img
video
input
type
因此,它确实映射到该aspect-ratio
属性。具体来说:
您可以将“表示性提示”视为有点像内部应用的零特异性内联样式。
这使用了aspect-ratio
我之前没有提到的一个特性:
.aspect-ratio-demo {
aspect-ratio: auto 16 / 9;
}
新位是auto
. 这是规范所说的:
如果同时指定auto和<ratio>,则首选纵横比是指定的宽度/高度比率,除非它是具有自然纵横比的替换元素,在这种情况下,将使用该纵横比。
很多文章都掩盖了这一点,可能是因为规范文本有点难以阅读,但它增加了一些重要的行为:
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 使用正确的width
并height
取决于使用的源,但 Firefox 将始终使用<img>
.
这是跟踪此问题的 Firefox 错误。希望它会很快得到修复!
那么,我们应该使用哪种方法呢?
好的,到目前为止,这篇文章一直是一个巨大的支线任务。现在我们到了实际点。而且,在我看来,答案是……没什么新鲜的。
我们有一个解决方案,aspect-ratio
它是基于 CSS 的。另一个解决方案是表示性提示,它使用width
和height
属性。这个问题非常类似于“这个图像应该是 a<img>
还是 CSS background-image
?” 答案是一样的:是内容还是设计?
如果我在博客上的文章中添加图片,那就是内容。我希望保留空间是内容的纵横比。如果我弄错了width
andheight
属性,我宁愿从内容图像中使用正确的值。因此,width
和height
属性感觉最合适。这意味着我可以只创作内容,而不需要深入研究内联样式。
如果设计要求图像的布局是特定的纵横比,那么aspect-ratio
在 CSS 中强制执行可能是合适的。例如,必须是一个英雄形象16 / 9
——如果形象不完全16 / 9
,我不希望它弄乱我的设计,我希望设计优先。虽然,如果图像实际上不是那个纵横比,它最终会被拉伸 ( object-fit: fill
)、信框 ( object-fit: contain
) 或裁剪 ( object-fit: cover
)。没有一个是理想的。
您可以使用aspect-ratio
和媒体查询来弥补 Firefox 在<picture>
艺术指导方面缺乏支持。但是,我希望他们能尽快修复这个错误,所以我们不需要破解它。
就是这样!我们花了十年的时间才真正解决了这个问题,但现在你可以使用width
和height
属性来避免布局转换,或者aspect-ratio
在 CSS 中,以最合适的为准。
来自 https://jakearchibald.com/2022/img-aspect-ratio/