仅仅一年多前,Chrome Aurora 团队推出了 Angular NgOptimizedImage 指令。该指南主要侧重于提升性能(以 Core Web Vitals 指标衡量)。它将常见的图片优化和最佳实践捆绑到一个面向用户的 API 中,该 API 的复杂程度与标准 <img>
元素相差无几。
2023 年,我们通过新功能增强了指南。本文将介绍其中最重要的一些新功能,重点介绍我们选择优先实现每项功能的原因,以及这些功能如何帮助提升 Angular 应用的性能。
新功能
NgOptimizedImage 在不断改进,其中包括以下新功能。
填充模式
通过提供 width
和 height
属性来调整图片大小,对于减少布局偏移而言是一项非常重要的优化,因为浏览器需要知道图片的宽高比,才能为其留出空间。不过,调整图片大小会给应用开发者带来额外的工作,对于某些图片用例来说,这并不合理。
在开发者预览版之后,我们为图片组件添加了第一个主要功能:填充模式,以帮助解决这一矛盾。这样,开发者无需明确设置图片大小,也无需导致布局偏移,即可添加图片。
在填充模式下,系统会停用图片大小要求,并自动为图片设置样式,使其填充其包含元素。这样,图片的宽高比就与其在页面上占据的空间分离了,您可以更好地控制图片如何适应页面布局。
填充模式使用 NgOptimizedImage 作为 background-image
CSS 属性的更高性能替代方案。将图片放置在 <div>
或其他原本具有 background-image
样式的元素内,然后启用填充模式,如上例代码所示。使用 <div>
上的 object-fit
和 object-position
CSS 属性来控制图片在背景中的放置方式。
// Height and width are required
<img ngSrc="example.com" height="300" width="400">
// Unless you use fill mode!
<div style="width: 100vw; height: 50em; position: relative">
<img ngSrc="example.com" fill>
</div>
Srcset 生成
最有效的图片优化技术之一是使用 srcset
属性,以确保为访问应用的任何设备下载尺寸合适的图片。在整个应用中使用 srcset
可以防止浪费带宽,并显著提升 LCP 核心网页指标。
srcset
属性的缺点是实现起来可能很麻烦。手动写出 srcset
值意味着向应用中的每个图片元素添加多行标记,并为每个 srcset
添加多个自定义网址。您还必须确定一组断点,这很复杂,因为它们既可以表示常见设备的屏幕密度,也可以表示视口大小。
因此,在 NgOptimizedImage 指令中添加自动 srcset 生成功能是发布后的一项重大里程碑。添加此功能后,使用支持图片大小调整的 CDN 的任何应用都可以在使用 NgOptimizedImage 指令生成的每个图片中自动添加可自定义的完整 srcset。
我们添加了一个简化的 API 来设置 sizes
属性,该属性用于确保每个图片都获得正确类型的 srcset
。如果您未添加 sizes
属性,我们会知道图片是固定大小的,并且应获取密度依赖的 srcset,如下所示:
<img src="www.example.com/image.png" srcset="www.example.com/image.png?w=400 1x, www.example.com/image.png?w=800 2x" >
这种 srcset 可确保图片的大小能根据用户设备的像素密度进行调整。
另一方面,如果您确实添加了 sizes
属性,NgOptimizedImage
会使用以下默认断点列表生成一个包含许多常见设备和图片尺寸的断点的自适应 srcset:
[16, 32, 48, 64, 96, 128, 256, 384, 640, 750, 828, 1080, 1200, 1920, 2048, 3840]
建立连接前生成
为了提高 LCP,请务必缩短用户下载 LCP 图片所花的时间。在上一部分中,您了解了 srcset
如何通过传输较小的图片文件来提供帮助,但同样重要的优化是尽快开始传输。一种方法是使用 link rel="preconnect"
代码快速建立与图片网域的连接。
从一开始,如果您未能预连接到 LCP 图片的网域,NgOptimizedImage 就会发出警告,但警告并不是理想的解决方案,我们更愿意直接为您解决问题。而 NgOptimizedImage 现在正是通过自动预连接生成来实现这一点。
为了支持此功能,我们使用静态代码分析来尝试检测 NgOptimizedImage 加载器中的图片网域,并为这些网域自动生成预连接链接代码。在某些情况下,可能仍需要手动预连接链接,但对于大多数用户而言,自动预连接意味着只需完成一个步骤即可获得良好的图片效果。
增强了对自定义加载器的支持
NgOptimizedImage 的一个关键元素是加载器架构,该架构允许指令自动生成专门针对应用的图片 CDN 的网址。包含一组适用于广泛使用的 CDN 的内置加载器。我们还支持使用自定义加载器,以便您将 NgOptimizedImage 与几乎任何图片托管解决方案集成。
在发布时,这些自定义加载器的范围受到限制,只能从图片元素读取 width
属性。根据用户反馈,我们添加了对可自定义的 loaderParams
数据结构的支持,这样便可将任意数据从图片元素传递到自定义加载器。扩展后,自定义加载器可以简单也可以复杂,具体取决于应用的映像基础架构。
以下示例展示了简单的自定义加载器如何使用 loaderParams
API 在两个备用图片网域之间进行选择:
const myCustomLoader = (config: ImageLoaderConfig) => {
if (config.loaderParams?.alternateDomain) {
return `https://alternate.domain.com/images/${config.src}`
}
return `https://primary.domain.com/images/${config.src}`;
};
如需查看更复杂的自定义加载器示例,请参阅 Angular 文档。
有关图片效果的更详细指南
到目前为止,我们向 Angular 添加的每项图片性能提醒都属于 NgOptimizedImage 指令。如果您未在应用中使用该指令,则不会收到有关图片性能问题的任何指导。
在 Angular 17 中,我们将扩大图片性能指南的适用范围,涵盖所有 Angular 应用。现在,如果我们检测到我们知道会影响性能的图片模式(例如延迟加载 LCP 图片或下载的文件比网页大得多),即使您未使用 NgOptimizedImage,我们也会通知您。
图片性能对所有应用都很重要,我们很高兴能够继续构建防护措施,以帮助防止 Angular 应用中出现常见错误。
展望未来
我们已经在努力为 NgOptimizedImage 开发下一组功能。虽然图片性能仍然是我们关注的核心问题,但我们还希望添加一些有助于提升开发者体验的功能,以确保 NgOptimizedImage 仍然是将图片添加到 Angular 应用中的理想选择。
我们优先考虑的一项功能是图片占位符。这些技术通常用于改善 Web 应用中的图片加载效果,但如果实现不当,可能会影响性能。我们希望在 NgOptimizedImage 中构建一个以性能为先的图片占位符系统。请密切关注我们的博客,了解后续公告!