记录 HTML 中与性能/渲染有关的几个新属性

mdn 对blocking 属性的解释:(实验性),这个属性明确指出,在获取脚本的过程中,某些操作应该被阻断。要阻断的操作必须是一个以空格分隔的列表,下面列出了阻断属性。

blocking属性允许我们能控制部分渲染的阻塞,直到特定的资源加载完毕。

使用

  • 可应用元素:<head> 标签中的 <script><link><style>
  • 值:"render"

设置blocking="render" 用于标记那些在显示任何内容给用户之前必须加载完成的资源。在这些资源加载完成之前,浏览器窗口中不会绘制任何像素。

<script>使用

如:

1
<script blocking="render" src="main.js" defer></script>

默认情况下,浏览器会为所有渲染阻塞的资源分配较高的优先级。但考虑到不是所有浏览器都支持 blocking 属性,添加 fetchpriority 属性设置 fetchpriority="high" 也是个不错的选择:

1
<script blocking="render" fetchpriority="high" src="main.js" defer></script>
内联脚本

blocking 属性同样适用于内联脚本。传统的内联脚本默认是阻塞的(deferasync 属性不适用于它们)。但是,如果你的脚本带有 type="module" 属性,即使是内联的,它也会延迟执行。

1
2
3
<script type="module" async blocking="render">
// 重要的 JavaScript 代码...
</script>

内联模块脚本中的 async 属性意味着它会尽快执行。

1
<link rel="stylesheet" href="main.css" blocking="render" />

可以在 <link> 元素上设置 blocking 属性。但如果你使用 <link> 配合 rel="preload" 来预加载资源,或者使用 rel="modulepreload" 来预加载 JavaScript 模块,那么 blocking 属性将不会生效。

开发者通常会利用这种行为来有意识地延迟非关键 CSS 的加载。但是,如果你需要以这种方式加载关键 CSS(会改变整个页面布局或影响页面折叠内容的样式),则可以使用 blocking 属性:

1
2
3
4
5
const link = document.createElement('link');
link.rel = 'stylesheet';
link.href = './styles.css';
link.setAttribute('blocking', 'render');
document.head.appendChild(link);

渲染阻塞 DOM 节点

HTML 的渲染是逐步/增量进行的:渲染可以在整个 HTML 文档被获取和解析之前就开始。

有一种方法可以根据特定 HTML 元素是否已解析来阻塞渲染。

<head> 中放置一个 <link>,其 href 属性引用所要元素的 id

1
2
3
4
5
6
7
8
9
10
<!DOCTYPE html>
<html>
<head>
<link rel="expect" href="#visually-critical-content" blocking="render" />
</head>
<body>
<header>...</header>
<div id="visually-critical-content">...</div>
</body>
</html>

这使得开发者可以更好地控制哪些内容包含在首次内容绘制 (FCP) 中。它应该只用于页面折叠之上的元素——否则你会不必要地延迟首次绘制。一旦元素被解析,页面就会对用户可见。如果找不到预期的元素,则在整个 HTML 文档解析完成时,渲染将被解除阻塞。

这个功能主要是在考虑跨文档视图转换的情况下添加到 Web 中的。

renderBlockingStatus 检测是否生效

如果你想验证 blocking 属性是否生效,可以在浏览器的开发者工具控制台中运行以下代码,来查看渲染阻塞资源的列表:

1
2
3
4
window.performance
.getEntriesByType('resource')
.filter(resource => resource.renderBlockingStatus === 'blocking')
.forEach(resource => console.log(resource.name));

那我们为什么需要这个新属性呢?

它明确了阻塞的行为,清晰地传达了开发者的意图,这样团队成员在重构代码时,就不会无意中把它改成非阻塞的了。
当与 deferasync 属性一起使用时,它可以阻塞渲染,同时不会阻塞 HTML 解析器的工作。
与传统脚本不同,模块脚本默认是延迟加载的。<script type="module"> 现在可以通过 blocking 属性来实现渲染阻塞。
通过 JavaScript 动态添加到 <head> 中的 <script><link><style> 元素,默认是不会阻塞渲染的。但现在,你可以灵活地让它们实现阻塞。

是否可能会延长 FCP?

渲染阻塞会延迟将像素绘制到屏幕上,所以你可能会想,这是否意味着用户就得盯着空白页面看。在快速的网络连接下,这种情况很少见。过去,在浏览网页时,经常会在页面间看到白色的闪烁。为了解决这个问题,浏览器开始使用绘制保持(paint holding)。绘制保持会让用户停留在上一个页面,并显示一个加载指示器,直到新页面的首次内容绘制 (FCP) 准备就绪。如果你延迟了 FCP,用户就会在上一个页面上多停留一会儿。绘制保持只持续很短时间。如果你延迟了 FCP 太久,就会显示一个空白的白色页面。对于速度慢的网站,在慢速的 3G 网络上,这种白色空白的“闪烁”可能会持续很长时间。

兼容情况

p-blocking


<img>/<iframe>标签的loading属性

mdn 对于图片loading 属性的解释:HTMLImageElement 的 loading 属性为一个字符串,它的值会提示 用户代理 告诉浏览器不在可视视口内的图片该如何加载。这样一来,通过推迟图片加载仅让其在需要的时候加载而非页面初始载入时立刻加载,优化了页面的载入。

可以控制资源的加载行为,减少初始页面加载时间。

使用

设置值为"eager"时(默认行为),eager 告诉浏览器当处理 <img> 标签时立即加载图片;设置值为lazy时告诉用户代理推迟图片加载直到浏览器认为其需要立即加载时才去加载。例如,如果用户正在往下滚动页面,值为 lazy 会导致图片仅在马上要出现在 可视视口中时开始加载。

load 事件的时机

<img>

load 事件在文档被完整的处理完成时触发。当图片使用立即加载 (默认值) 时,文档中的所有图片都会在 load 事件触发前载入。

当 loading 值设为 lazy 时,图片不再会在请求,下载,处理的时间内推迟 load 事件触发。

loading 属性值设为 lazy 但是在页面初次加载时就在可视视口内的图片会立即加载但它们也不会推迟 load 事件。换句话说,这些图片不会在处理 元素时立即加载,但仍会作为页面初始加载的一部分而加载。他们只是不会影响 load 事件。

这表明当 load 触发时,可视区域内懒加载的图片可能不可见。

<iframe>

即使 iframe 位于可视视口并在页面加载时被请求,懒加载的 iframe 也不会影响 load 事件的时机。只有当文档中所有立即加载的 iframe 都被请求后,才能触发 load 事件。

<img>使用

1
<img src="image.jpg" loading="lazy" />
防止元素在图片懒加载时出现移位

当一个加载被 loading 属性设为 lazy 的图片最后加载时,浏览器会根据<img> 元素的尺寸和图片自身大小重排文档,更新被图片影响的元素的位置。

为了防止重排发生,你需要使用 widthheight 属性明确设置图片大小。通过这样建立固有长宽比,你防止了元素的移位。取决于实际的加载时间和重排,移位造成的最小的影响可能只是使用户困惑和不适,最坏的影响则是导致用户点错目标。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function addImageToList(url) {
const list = document.querySelector('div.photo-list');

let newItem = document.createElement('div');
newItem.className = 'photo-item';

let newImg = document.createElement('img');
newImg.loading = 'lazy';
newImg.width = 320;
newImg.height = 240;
newImg.src = url;

newItem.appendChild(newImg);
list.appendChild(newItem);
}

iframe 使用

1
<iframe src="example.html" loading="lazy"></iframe>

以下示例展示了如何定义一个懒加载的 iframe,然后将其附加到文档中的 <div>。只有当 iframe 即将变得可见时,才会加载 iframe

1
2
3
4
5
6
7
8
9
10
// 在 iframe 中定义懒加载
const iframe = document.createElement('iframe');
iframe.src = 'https://example.com';
iframe.width = 320;
iframe.height = 240;
iframe.loading = 'lazy';

// 添加到类名为 frameDiv 的 div 元素中
const frameDiv = document.querySelector('div.frameDiv');
frameDiv.appendChild(iframe);

兼容情况

p-loading


mdn 对hreflang 属性的解释:此属性指明了被链接资源的语言。其意义仅供参考。可取的值参见 RFC 5646: 语言识别标签(又称 BCP 47)。仅当设置了 href 属性时才应设置该属性。

hreflang属性指定<a><link>元素上链接资源的语言。它的工作原理类似于lang 属性,但专门用于链接。

您可以通过在内部和外部网站链接中使用 hreflang 来改善用户体验和 SEO。在内部网站链接上使用 hreflang 提供了一种方法,可以告诉搜索引擎其他语言或地区的页面的不同变化。这意味着讲英语的人将收到该网站的英文版,而讲瑞典语的人将收到瑞典文版。用户端无需手动切换,体验更加流畅。

使用

将带有所需 ISO 语言代码的 hreflang 属性添加到<a>元素中。对于英文网站则是 en

1
<a href="https://example.com" hreflang="en">English Website</a>

您也可以使用更具体的语言代码,并使用区域变化。例如我们可以为英式英语添加 en-GB

1
<a href="https://example.at" hreflang="en-GB">English Website</a>

如果您的网站提供多种语言版本,您可以使用 hreflang 指定与特定 URL 关联的文档的语言和区域。添加该属性将有助于搜索引擎了解不同网页版本的语言和区域定位。

在每个链接中添加带有所需语言代码的 hreflang。一个链接应该作为默认的后备版本,通过添加 hreflang="x-default"而不是语言代码来识别。最后对于语言切换器中的每个链接,将 rel 属性的值设置为"alternate",以指示所链接的页面是当前页面的替代页面。

1
2
<link href="https://example.com" rel="alternate" hreflang="x-default" />
<link href="https://example.com/de" rel="alternate" hreflang="de" />

您也可以在语言切换器中使用 hreflang

1
2
<a href="https://example.com" hreflang="x-default">English</a>
<a href="https://example.com/de" hreflang="de">German</a>

有时语言切换者使用他们切换到的语言中的链接文本。您可以通过额外使用 lang 属性来指示这一点。

1
2
<a href="https://example.com" hreflang="x-default">English</a>
<a href="https://example.com/de" hreflang="de" lang="de">Deutsch</a>

增强可访问性的另一种方法是将 aria-current="true"包含到当前活动的链接中。

1
2
<a href="https://example.com" hreflang="x-default" aria-current="true">English</a>
<a href="https://example.com/de" hreflang="de" lang="de">Deutsch</a>

兼容情况

p-blocking


通用属性translate

mdn 对translate 属性的解释:全局属性 translate 是一种枚举属性,用来规定对应元素的可翻译属性值及其 Text 子节点内容是否跟随系统语言作出对应的翻译变化。

translate 属性用于指示元素是否应该被翻译。

为什么使用 translate?

默认情况下,大多数网站文本都是可翻译的(除了一些例外,例如图像上或 SVG 中的文本)。如果网站的定义语言与浏览器的默认语言不同,翻译工具(如 Google 翻译)可能会建议翻译页面内容。

但可能存在这种行为是不需要的情况。公司名称、电子邮件地址或代码示例等特定术语通常不应翻译,以避免混淆。自动翻译并不总是完全准确的,特别是对于小众词汇或技术词汇。

使用

您可以在任何 HTML 元素上使用 translate。指定一个空字符串("")或 yes 用于翻译,而 no 用于避免翻译。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<!-- 德语原文 -->
<p>
<span>Wien<span>
ist (wieder) die lebenswerteste Stadt der Welt!
</p>
<p>
<span translate="no">Wien<span>
ist (wieder) die lebenswerteste Stadt der Welt!
</p>

<!-- 翻译后 -->
<p>
<span>Vienna<span>
named world's most liveable city (again)!
</p>
<p>
<span translate="no">Wien<span>
named world's most liveable city (again)!
</p>

兼容情况

p-translate.png


相关链接