延迟加载最佳实践

延迟加载图片和视频,可带来可衡量的正面效果 好处,但这并不是一件轻而易举的任务。如果弄错了 可能产生的意外后果。因此,请务必 关注度。

注意首屏

开发者可能会很想以如下方式延迟加载网页上的每个媒体资源: 但您需要抵制住这种诱惑。高于 折叠不应延迟加载。应将此类资源视为 资源,因此应正常加载。

延迟加载将资源加载延迟到 DOM 可交互之后再加载 当脚本加载完毕并开始执行时。对于 也没关系,但首屏关键资源应使用 标准 <img> 元素,以便尽快显示这些元素。

当然,如今,网站并不是很清楚 用户在众多不同尺寸的屏幕上观看广告笔记本电脑上首屏上的内容 在移动设备上可能位于其下方。目前还没有关于 在任何情况下都能以最佳方式解决这个问题。您需要进行 网页关键资源的清单,然后使用常规版式加载这些图片, 。

此外,您可能并不希望对折叠线过于严格 触发延迟加载的阈值它可能更适合您的用途 在首屏线以下一定距离内建立缓冲区,以便图片可以开始 在用户将其滚动到视口之前,确保加载完成。例如, 借助 Intersection Observer API,您可以在rootMargin options 对象。IntersectionObserver这个 从而有效地为元素提供缓冲区,以便在 该元素位于视口中:

let lazyImageObserver = new IntersectionObserver(function(entries, observer) {
  // lazy-loading image code goes here
}, {
  rootMargin: "0px 0px 256px 0px"
});

如果 rootMargin 的值与您为 CSS 指定的值相似 margin 属性,那是因为它!在这种情况下, 被观察元素的下边距(默认为浏览器视口,但 可以使用 root 属性将其更改为特定元素)并将其拓展到 256 像素。这意味着,当图片元素被覆盖时, 距离视口 256 像素以内 图片就会开始加载 在用户实际看到之前。

要在不支持 Intersection Observe 的浏览器中实现同样的效果,请使用滚动事件处理代码,并调整 getBoundingClientRect 检查以包含缓冲区。

布局偏移和占位符

如未使用占位符,延迟加载媒体可能会导致布局偏移。 这些更改可能会让用户感到迷惑,并触发代价高昂的 DOM 布局 消耗系统资源并导致卡顿的操作。至少 可以考虑使用与 目标图像或 LQIP 或 提示媒体内容的 SQIP

对于 <img> 标记,src 最初应指向一个占位符,直到 属性会更新为最终图片网址。在poster 指向占位符图片的 <video> 元素。此外,请使用 width<img><video> 标记中的 height 属性。这样可以确保 从占位符转换为最终图片不会改变渲染大小 该元素在媒体加载时显示

图像解码延迟

在 JavaScript 中加载大型图片并将其放到 DOM 中可能会占用 主线程,这会导致界面在短时间内无响应 解码期间。使用 decode 异步解码图片 方法 以便减少此类卡顿现象, 请注意:该方法尚未在所有国家/地区推出,而且会增加延迟加载逻辑的复杂性。 如果您想使用它,则需要先进行检查。下方显示了 如何使用 Image.decode() 进行回退:

var newImage = new Image();
newImage.src = "my-awesome-image.jpg";

if ("decode" in newImage) {
  // Fancy decoding logic
  newImage.decode().then(function() {
    imageContainer.appendChild(newImage);
  });
} else {
  // Regular image load
  imageContainer.appendChild(newImage);
}

请访问此 CodePen 链接,了解 代码。如果大多数图片都相当小 这样做的用处不大 延迟加载大图片并将其插入 DOM。

内容无法加载时

有时,媒体资源会因为某种原因而加载失败,并且会出错 情况。何时可能会发生这种情况?视情况而定,但以下是一种假设场景 适合您的情况:您设置了短时间的 HTML 缓存政策(例如, 分钟),而用户访问了网站,或者用户打开了一个过时的标签页 然后再回来阅读您的内容。 在此过程中的某些时候,会发生重新部署。在此部署过程中, 映像资源的名称因基于哈希的版本控制而发生更改,或已被移除 当用户延迟加载图片时, 不可用,因此会失败

虽然此类情况比较少见,但您可能需要 对于图像,这种解决方案可能类似于 :

var newImage = new Image();
newImage.src = "my-awesome-image.jpg";

newImage.onerror = function(){
  // Decide what to do on error
};
newImage.onload = function(){
  // Load the image
};

发生错误时采取何种做法取决于您的应用。对于 例如,可以将图片占位符替换为 用户尝试重新加载图片,或只显示错误消息 。

还可能会出现其他情况。无论你做什么,从来都不是一个坏主意 在发生错误时向用户发出信号,并可能为用户提供相应的操作 在出现问题时采取的行动。

JavaScript 可用性

不应假定 JavaScript 始终可用。如果您要 延迟加载图片,不妨考虑提供 <noscript> 标记,以 JavaScript 不可用的情况。最简单的后备示例包括 在 JavaScript 处于关闭状态时,使用 <noscript> 元素传送图片:

我是图片!

如果 JavaScript 已关闭,用户将同时看到占位符图片和 包含 <noscript> 元素的图片。要解决这一问题,请将 <html> 标记上的 no-js 类,如下所示:

<html class="no-js">

然后,在 <head> 中的任何样式表前面放置一行内嵌脚本 通过 <link> 标记请求,这些标记会从 <html> 中移除 no-js 类 元素:

<script>document.documentElement.classList.remove("no-js");</script>

最后,当出现以下情况时,使用一些 CSS 隐藏具有 lazy 类的元素 JavaScript 不可用:

.no-js .lazy {
  display: none;
}

这不会阻止占位符图片加载,但结果会 理想。关闭 JavaScript 的用户不止会获得占位符 这要优于使用占位符和 全部。