Angular NgOptimizedImage 指令的新变化

Alex Castle
Alex Castle

就在一年前,Chrome Aurora 团队发布了 Angular NgOptimizedImage 指令。该指令主要侧重于根据核心网页指标指标提高性能。它将常见的图片优化和最佳实践捆绑到一个面向用户的 API 中,并不比标准 <img> 元素复杂得多。

2023 年,我们在该指令中增加了一些新功能。此博文介绍了这些新功能中最重要的功能,并强调了我们选择优先处理每项功能的原因,以及这些功能如何帮助提升 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 可以防止浪费带宽,并可显著提高 LCP Core Web Vitals

srcset 属性的缺点是实现起来可能会很麻烦。手动写出 srcset 值意味着向应用中的每个图片元素添加多行标记,并为每个 srcset 添加多个自定义网址。此外,您还必须确定一组断点,这很复杂,因为它们可以同时表示屏幕密度和常见设备的视口大小。

因此,在 NgOptimizedImage 指令中添加自动生成 srcset 是发布后的一个重大里程碑。添加之后,任何使用支持调整图像大小的 CDN 的应用程序都可以获得完整的、可自定义的 srcset,自动添加到使用 NgOptimizedImage 指令生成的每个图像中。

我们添加了一个用于设置 sizes 属性的简化 API,该属性用于确保每张图片都能获得正确类型的 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 中建立性能优先的图片占位符系统。请持续关注我们的博客,了解更多公告!