Angular NgOptimizedImage 指令的新变化

亚历克斯城堡
Alex Castle

一年多前,Chrome Aurora 团队发布了 Angular NgOptimizedImage 指令。该指令主要侧重于提高性能(根据核心网页指标指标进行衡量)。它将常见的图片优化和最佳做法捆绑在一个面向用户的 API 中,该 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 属性来确保为访问您应用的设备下载适当大小的图片。在整个应用中使用 srcset 不仅可以避免浪费带宽,还可以显著提高 LCP Core Web Vitals

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

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

我们添加了用于设置 sizes 属性的简化 API,该 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 中构建性能优先的映像占位符系统。敬请关注我们的博客,及时了解最新公告!