Angular NgOptimizedImage 指令的新变化

Alex Castle
Alex Castle

仅仅一年多前,Chrome Aurora 团队推出了 Angular NgOptimizedImage 指令。该指南主要侧重于提升性能(以 Core Web Vitals 指标衡量)。它将常见的图片优化和最佳实践捆绑到一个面向用户的 API 中,该 API 与标准 <img> 元素相比并不复杂。

2023 年,我们通过新功能增强了directive。本文介绍了这些新功能中最实用的功能,重点介绍了我们选择优先实现每项功能的原因,以及这些功能如何帮助提高 Angular 应用的性能。

新功能

NgOptimizedImage 已经过显著改进,其中包括以下新功能。

填充模式

通过提供 widthheight 属性来调整图片大小,对于减少布局偏移而言是一项非常重要的优化,因为浏览器需要知道图片的宽高比,才能为其留出空间。不过,对应用开发者来说,调整图片大小是一项额外的工作,对于某些图片用例,没有意义。

在开发者预览版之后,我们向图片组件添加了第一个主要功能:填充模式,以帮助解决这一矛盾。这样,开发者无需明确设置图片大小,也不会导致布局偏移,即可添加图片。

在“填充”模式下,系统会停用图片大小要求,并自动为图片设置样式,使其填充其包含元素。这样,图片的宽高比就与其在页面上占据的空间分离了,您可以更好地控制图片如何适应页面布局。

填充模式使用 NgOptimizedImage 作为 background-image CSS 属性的更高性能替代方案。将图片放置在 <div> 或其他原本具有 background-image 样式的元素内,然后启用填充模式,如上例代码所示。使用 <div> 上的 object-fitobject-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 中建立性能优先的图片占位符系统。请持续关注我们的博客,了解更多公告!