面试导航 是一个专注于前、后端技术学习和面试准备的 免费 学习平台,提供系统化的技术栈学习,深入讲解每个知识点的核心原理,帮助开发者构建全面的技术体系。平台还收录了大量真实的校招与社招面经,帮助你快速掌握面试技巧,提升求职竞争力。如果你想加入我们的交流群,欢迎通过微信联系:
yunmz777
。
CLS(Cumulative Layout Shift) 是 Web Vitals(Web 核心指标)之一,它衡量页面加载过程中内容发生的布局偏移。它用于反映在页面加载期间,用户视图中出现的“意外的布局变化”程度。这些变化可能导致页面内容移动,影响用户体验。
CLS 关注的是当网页的内容在页面加载过程中重新排列或跳动时,这些变动对用户的影响程度。例如,如果在加载网页时,按钮突然移动到另一个位置,或者一张图片加载时其他内容被推走,这就是一种 布局偏移,可能会让用户感到困惑或不适。
布局偏移通常会给用户带来不好的体验,特别是当用户正在查看网页或点击按钮时。如果某个按钮突然跳到页面的另一个位置,用户可能会不小心点击到错误的内容。这样的布局跳动会让用户感到困惑、沮丧,甚至导致网页操作失败。
为了提供良好的用户体验,网站应尽力使 CLS 得分不高于 0.1。为确保大多数用户都能达到此目标值,一个合适的衡量阈值是网页加载时间的第 75 个百分位数,并按移动设备和桌面设备进行细分。
布局偏移
布局偏移(Layout Shift) 是指在页面加载或交互过程中,页面中某个或多个元素的布局突然发生变化的现象。这种变化可能会导致页面内容的位置或尺寸发生意外调整,影响用户的阅读或交互体验。
布局偏移通常是由于页面的 异步加载 或 动态内容插入 引起的,特别是在以下情况下:
-
异步加载的内容:如图片、广告、字体、视频等,在这些资源加载之前,浏览器并没有为其预留足够的空间。加载完成后,页面的其他内容会因为新元素的加入而发生位置调整。
-
动态内容插入:如 JavaScript 在页面加载后动态插入内容。如果没有为这些内容预留空间,页面内容会发生变化。
-
字体加载:网页中使用的 Web 字体在加载时,如果没有提前为其预留空间,可能导致页面文字的大小或位置变化,产生布局偏移。
-
动画效果:在元素位置、大小等属性上应用动画时,可能会导致页面布局的突变,尤其是如果没有控制动画的时机或容器大小时。
布局偏移分数
布局偏移数 也称为 布局偏移得分(Layout Shift Score),用来衡量每次元素的布局偏移。它反映了页面上某个或多个元素发生意外位移的程度。这个得分是通过计算布局偏移的 影响面积 和 偏移距离 得到的。
布局偏移得分的计算公式如下:
[ \text{Layout Shift Score} = \text{影响区域面积的比例} \times \text{偏移的距离} ]
在上面的公式中:
-
影响区域的面积:指的是发生变化的元素所占的页面视口区域大小的百分比。如果是大面积变化,得分就较高。
-
偏移的距离:是元素在屏幕上偏移的距离,通常为水平和垂直方向上的位移。偏移的距离越大,得分越高。
例如,一个按钮或文本框的突然移动,影响到页面内容的布局,这就会增加布局偏移数。
撞击分数
撞击分数 主要关注页面元素的偏移是否对用户交互产生了负面影响,尤其是 当页面元素被移开时,是否影响到了用户正在操作的元素。例如,用户正在点击一个按钮,然而按钮由于某种动态内容的加载而突然移动,导致用户点击了错误的位置。
撞击分数的目的是衡量 这些布局变化对用户交互的干扰程度。撞击分数越高,表示布局变化越容易干扰用户操作。
在图示中,初始状态下,页面中的一个元素占据了视口的 50%,即该元素在屏幕上占据了一半的空间。接着,在下一个画面中,元素发生了 25% 的垂直位移,也就是说,它向下移动了视口高度的四分之一。这时,元素的布局发生了偏移,导致页面内容的意外变化,影响了用户的视觉稳定性。图中的 红色虚线矩形 表示该元素在两个帧中可见区域的并集,也就是说,元素的初始可见区域和移动后的可见区域合起来,占据了 视口的 75%。因此,这个布局偏移的 影响区域 是页面的 75%。
根据布局偏移得分的计算公式,影响区域占视口的 75%,而元素的偏移距离为 25%,这意味着布局偏移的影响较大。得分计算时,影响区域的比例与元素的移动距离相乘,这就表明布局偏移的得分和影响范围都很显著,用户的阅读或交互体验可能会受到影响。在这种情况下,页面的稳定性差,用户可能会因为元素位置变化而发生误操作,导致页面的用户体验变差。因此,减少这种布局偏移,确保页面在加载过程中保持视觉稳定性,是提升用户体验的重要方面。
距离分数
距离分数 是用来衡量布局偏移时,页面元素的 移动距离 对布局变化的影响程度。换句话说,距离分数计算的是 元素偏移的实际距离,即元素在页面上发生位移的量。偏移的距离越大,对用户体验的影响 就越显著,距离分数也越高。
距离分数 主要依赖于以下两个因素:
-
元素的偏移距离:即元素在页面上发生的水平和垂直方向的位移。偏移的距离越大,距离分数越高。
-
影响区域的面积:指元素在页面中占据的区域,影响的区域越大,得分越高。
距离分数的计算方式是通过元素在页面上 水平和垂直偏移的距离 来衡量的。通常情况下,偏移的距离越大,意味着该布局变化对页面的视觉稳定性影响越大,用户的体验会变得更加不稳定。
它的计算公式如下:
[ \text{距离分数} = \text{偏移的距离} \times \text{影响区域的面积比例} ]
在这个公式中:
-
偏移的距离:指元素发生的水平或垂直位移。例如,如果元素移动了页面的一部分,这个距离就会影响到得分。
-
影响区域的面积比例:指页面中受影响区域的面积相对于页面总视口面积的比例。
根据图示,页面中的元素发生了垂直位移,导致页面布局发生了变化。为了衡量这种布局偏移对用户体验的影响,我们需要计算 距离分数(Distance Score)。计算公式 为:
[ \text{距离分数} = \text{偏移的距离} \times \text{影响区域的面积比例} ] [ = 0.25 \times 0.75 ] [ = 0.1875 ]
在这个例子中,元素的 偏移距离 是 25%,即该元素在视口中向下或向上移动了 视口高度的 25%。同时,影响区域的面积比例 是 0.75,因为红色虚线矩形代表的是该元素在两个帧中的可见区域的并集,占据了视口的 75%。将这些数值代入公式,我们可以得出 距离分数为 0.1875。
这个结果表明,虽然元素发生了位移,影响的区域较大,但相对于页面总视口面积,偏移距离适中,因此 距离分数为中等,对页面的视觉稳定性产生了适度影响。为了优化用户体验,可以减少这种类型的布局偏移,确保元素的稳定性,以避免影响用户交互。
示例
以下示例展示了向现有元素添加内容如何影响布局偏移得分:
根据图示,按钮的插入导致页面发生了布局偏移。在初始状态下,按钮并未显示在 DOM 中,因此没有影响页面布局。按钮显示后,占据了页面视口的 50%,并且其偏移了视口 14% 的区域。根据计算公式,撞击分数为 影响区域的面积比例 × 偏移的距离,即:
[ \text{撞击分数} = 0.5 \times 0.14 = 0.07 ]
这表示按钮的插入对页面布局的影响较小,撞击分数为 0.07,属于较低影响的范围。尽管按钮占据了页面的一部分空间,并且有一定的位移,但整体来说,页面的视觉稳定性和交互性没有受到严重干扰。通过计算撞击分数,可以量化布局偏移对用户操作的影响,帮助开发者更好地优化页面的稳定性,避免用户在交互过程中遇到问题。
以下示例展示了多个不稳定元素如何影响网页的布局偏移得分:
在这个例子中,初始状态下页面显示了一个包含四个项目的列表:Cat、Dog、Horse 和 Zebra。随着新项目(Crocodile、Elephant、Lion 和 Tiger)的动态添加,页面布局发生了变化,因为这些新项目不在原始 DOM 中,它们插入后导致原有列表项的位置发生了偏移。影响区域占视口的 60%,而由于新元素的插入,页面内容发生了 30% 的垂直位移。
计算撞击分数时,影响区域的面积比例为 0.60,偏移的距离为 0.30,根据公式:
[ \text{撞击分数} = 0.60 \times 0.30 = 0.18 ]
因此,撞击分数为 0.18,表明布局偏移对页面的影响属于中等程度。虽然新元素插入导致了页面变化,但由于 影响区域较大,并且 内容发生了较大的垂直位移,这种布局变动可能会对用户的视觉体验产生影响,尤其是在用户操作时,可能导致误点击或无法顺利浏览。为了减少这种影响,开发者可以优化内容插入的方式或预留足够空间来避免布局变化。
预期布局偏移与意外布局偏移
并非所有布局偏移都是不好的。事实上,许多动态 Web 应用都会频繁更改网页上元素的起始位置。只有在用户未预料到的情况下,布局偏移才会带来负面影响。
用户发起的布局偏移
用户发起的布局偏移 是指用户与页面交互时(如点击按钮、输入文字等)触发的布局变化。这类布局偏移通常是可以接受的,因为它们是用户操作的一部分,前提是布局偏移发生的时机和方式能让用户清楚地感知到二者之间的关系。比如,当用户点击某个按钮后,页面可能需要展示新的内容或更新现有元素,这时候页面布局的变化是预期之内的。
为了确保这种布局偏移不影响用户体验,偏移发生的时机非常重要。如果用户触发了一个需要一些时间才能完成的操作(如发起网络请求),最好提前为加载的内容预留空间并显示加载指示器。这样,用户就能清楚地知道内容正在加载,避免因布局变化而产生混乱。如果没有及时反馈,用户可能会误点击其他内容,导致这些内容消失或无法正确交互。
此外,在用户输入后 500 毫秒 内发生的布局偏移会被标记为 hadRecentInput
,从而不被计算为意外布局变化。这是因为这种偏移通常与用户操作紧密相关,不会被视为干扰。总的来说,用户发起的布局偏移 是一种正常的交互行为,只要在合适的时机进行反馈并预留空间,就能提供更流畅的用户体验。
动画和过渡
动画和过渡效果在网页设计中可以大大改善用户体验,特别是当它们帮助用户理解页面内容的变化时。如果处理得当,动画和过渡效果能使网页内容在更新时显得更加自然流畅,而不会让用户感到意外或困惑。与突然发生的布局偏移相比,渐进的动画效果能清楚地向用户传达页面状态的变化,从而增强页面的可用性。
例如,当页面元素需要移动或改变时,使用动画效果让元素从一个位置平滑过渡到另一个位置,可以帮助用户直观地理解这些变化。而如果页面元素突然偏移,通常会导致用户体验变差,因为这种突如其来的变化让用户难以理解为何内容发生了改变。渐变和过渡动画能更好地引导用户的注意力,让他们清晰地看到变化的过程。
在实现动画时,使用 CSS 的 transform
属性 是一种避免触发布局偏移的最佳方式。比如,使用 transform: scale()
来改变元素的大小,而不是直接修改元素的 height
或 width
属性,因为后者会导致页面重新计算布局,从而引起不必要的布局偏移。类似地,当需要移动页面元素时,应该使用 transform: translate()
而不是更改元素的 top
、right
、bottom
或 left
属性。后者会改变元素的定位,可能导致布局偏移,进而影响页面的稳定性和用户体验。
总之,动画和过渡效果可以极大地提升用户体验,但必须谨慎使用,特别是要遵守用户的浏览器设置,并选择不会引起布局偏移的方式来实现这些效果。
如何衡量 CLS
在前面的内容中我们都知道,CLS 是所有布局偏移的得分的累积,每个布局偏移都有一个得分,计算公式如下:
[ \text{布局偏移得分} = \text{偏移的距离} \times \text{影响区域的面积比例} ]
累积布局偏移(CLS) 是指 所有布局偏移得分 的总和,计算公式如下:
[ \text{CLS} = \sum (\text{每次布局偏移的得分}) ]
假设页面上有两个元素分别发生了布局偏移:
-
元素 A:
- 影响区域的面积比例:0.3(即该元素影响了页面视口的 30%)
- 偏移的距离:0.2(即该元素偏移了 20% 的视口高度)
该元素的布局偏移得分为: [ \text{得分 A} = 0.3 \times 0.2 = 0.06 ]
-
元素 B:
- 影响区域的面积比例:0.5(即该元素影响了页面视口的 50%)
- 偏移的距离:0.1(即该元素偏移了 10% 的视口高度)
该元素的布局偏移得分为: [ \text{得分 B} = 0.5 \times 0.1 = 0.05 ]
最终,CLS 的计算为:
[ \text{CLS} = \text{得分 A} + \text{得分 B} = 0.06 + 0.05 = 0.11 ]
在 JavaScript 中衡量布局偏移
在 JavaScript 中,衡量布局偏移通常是通过监听 layoutshift 事件并计算布局偏移得分来实现的。这个过程是利用 PerformanceObserver API 来监控和捕捉布局偏移事件,并通过 LayoutShift 接口来获取布局偏移的数据。
以下是一个简单的代码示例,展示如何使用 PerformanceObserver 来监听并计算布局偏移:
// 设置 PerformanceObserver 来监听 layout-shift 事件
const observer = new PerformanceObserver((entryList, observer) => {
let cls = 0; // 初始化累计布局偏移(CLS)
// 遍历所有的布局偏移事件
entryList.getEntries().forEach((entry) => {
// 获取布局偏移的影响区域比例
const impactArea = entry.value;
// 获取偏移的距离
const distance = entry.distance;
// 计算布局偏移得分
const shiftScore = impactArea * distance;
cls += shiftScore; // 累加到 CLS 得分
console.log(`布局偏移得分: ${shiftScore}`);
console.log(`累计 CLS: ${cls}`);
});
});
// 启动 PerformanceObserver 来监听 layout-shift 事件
observer.observe({ type: "layout-shift", buffered: true });
在 JavaScript 中衡量 CLS
使用 web-vitals
库来衡量 CLS
(Cumulative Layout Shift)非常简单高效。通过调用 getCLS()
函数,可以轻松捕获页面的布局偏移数据。该函数会自动监测并计算页面中所有的布局偏移,并提供一个累积的 CLS 值,表示页面加载过程中的视觉稳定性。
在使用时,getCLS()
会返回一个 metric 对象,包含 CLS 值和其他相关信息。CLS 值是衡量页面布局偏移的一个得分,值越高,表示页面发生了更多的不稳定布局变化,可能会影响用户体验。通过监听 getCLS()
返回的数据,开发者可以实时获取页面的视觉稳定性,进而优化页面的布局,减少不必要的布局偏移。
例如,以下代码展示了如何使用 getCLS()
获取和记录页面的 CLS 值:
import { getCLS } from "web-vitals";
getCLS((metric) => {
console.log("CLS:", metric.value);
});
该示例会在控制台输出页面的 CLS 值。你可以进一步将该数据发送到分析服务器,用于监控和优化页面的性能。通过这种方式,开发者可以有效地追踪和优化页面的视觉稳定性,提升用户体验。
如何优化 CLS
在优化 CLS(Cumulative Layout Shift) 时,特别是在动画和过渡效果方面,以下详细策略可以帮助你更好地控制布局偏移,确保页面加载和用户交互过程中的视觉稳定性。
避免通过修改布局属性引起动画
当使用动画或过渡效果时,涉及布局属性的变化(如 height
、width
、top
、left
等)通常会导致页面的重排(reflow),并触发布局偏移。这种偏移会影响页面的 CLS 值,导致视觉不稳定。
如下是一些优化策略:
使用 transform
或 opacity
来进行动画。与传统的 top
、left
或 height
等属性不同,transform
不会触发布局的重排(reflow),而只是改变元素的呈现方式。
例如, 使用 transform
进行位移,而不是直接修改元素的 top
或 left
,使用 transform: translate()
来平移元素。translate()
不会引发布局重排,因此页面其他内容不会被推移,减少布局偏移。
/* 使用 translate() 移动元素 */
.element {
transform: translateX(100px); /* 水平平移100px */
}
使用 opacity
来淡入淡出元素,而不是通过 visibility
或 display
属性来控制元素的显示与隐藏。opacity
可以实现平滑过渡而不引起布局的重新计算。
.element {
opacity: 0;
transition: opacity 0.5s ease;
}
.element.visible {
opacity: 1;
}
合理控制动画的时机和过渡效果
动画和过渡效果可以有效改善用户体验,但如果使用不当,可能会对页面的稳定性产生负面影响。例如,如果动画效果导致页面在用户操作时发生布局偏移,可能会导致 CLS 值增加。
如下是一些优化策略:
-
确保动画效果的触发与页面加载过程或用户交互行为之间保持良好的同步。动画应该发生在用户明确的交互之后,而不是在页面加载时突如其来地发生。例如,避免在用户未操作时展示动画,避免让用户在等待时看到页面内容的跳动。
-
使用
prefers-reduced-motion
媒体查询,根据用户的设置来减少动画的复杂度,或者完全禁用某些动画效果。@media (prefers-reduced-motion: reduce) { .element { transition: none; /* 禁用过渡效果 */ } }
为图片和广告内容预留空间
图片和广告内容常常是 CLS 增加的原因之一,尤其是当这些内容没有为其设置固定尺寸时,浏览器在图片或广告加载时无法为它们预留足够的空间。这样,页面的其他元素就可能发生位移。
如下是一些优化策略:
-
为图片预设尺寸,为所有动态加载的图片、视频或广告元素设置明确的
width
和height
,以确保浏览器能够为它们预留固定的空间,防止它们加载完成后推移页面其他内容。<img src="image.jpg" width="600" height="400" alt="Image description" />
-
对于尚未加载的图片,可以使用占位符或骨架屏(Skeleton Screens)来为加载内容预留空间。这样,即使内容加载延迟,用户也能看到一致的页面结构。
<div style="width: 600px; height: 400px; background: #e0e0e0;"> <!-- 图片加载前的占位符 --> </div>
广告和嵌入内容的处理
广告、嵌入式内容(如嵌入视频或其他第三方小组件)的加载和展示也是导致 CLS 增加的常见原因,尤其是在没有为广告位预留足够空间时,广告内容的插入可能会导致页面其他元素的位移。
如下是一些优化策略:
-
确保广告容器的尺寸,无论广告是静态的还是动态加载的,都应该为广告位设置 固定的尺寸,并预留足够空间。这样,广告加载完成时不会影响页面的布局。
<div style="width: 300px; height: 250px;"> <!-- 广告内容 --> </div>
-
对于广告内容,可以使用异步加载的方式,避免广告加载时导致的布局偏移。可以通过
async
或defer
属性来延迟广告的加载时间,确保其不会影响页面的其他内容。
使用字体加载优化减少 CLS
自定义字体的加载可能会导致 CLS 增加,尤其是在字体尚未加载完成时,文本会出现闪烁或跳动现象。
如下是一些优化策略:
-
使用
font-display: swap
,确保字体加载时,浏览器会使用备用字体直到自定义字体加载完成后再切换。这可以有效减少因字体加载延迟引起的视觉跳动。@font-face { font-family: "MyCustomFont"; src: url("myfont.woff2") format("woff2"); font-display: swap; /* 字体加载时使用备用字体 */ }
避免大规模的 DOM 插入或删除
页面在加载时或在用户交互后,可能会大量插入或删除 DOM 元素,这会导致页面重新计算布局并引发布局偏移,增加 CLS。
如下是一些优化策略:
-
使用 懒加载 或 虚拟滚动 来按需加载内容。这样,页面不必一次性加载所有内容,避免大量 DOM 元素的突然插入或删除。
-
分步加载,例如,先加载重要的内容,然后逐步加载不那么重要的内容,以避免页面的整体布局发生剧烈变化。
使用 CSS Grid 和 Flexbox 布局
与传统的 position
或 float
布局相比,CSS Grid 和 Flexbox 更加稳定并能更好地处理响应式布局,减少因布局问题引起的偏移。
如下是一些优化策略:
-
使用 CSS Grid 或 Flexbox 来进行布局,这些现代的布局方式可以确保元素根据可用空间和其他元素自动调整,减少不必要的布局偏移。
.container { display: flex; flex-direction: column; }
小结
优化 CLS 需要关注所有可能导致布局偏移的因素,特别是在涉及 动画和过渡效果 时。通过避免修改会影响布局的属性(如 top
、left
和 height
),使用 transform
和 opacity
来进行动画,合理控制动画时机,并确保动态内容(如图片、广告、视频)在加载前预留空间,可以显著减少 CLS,提升页面的视觉稳定性和用户体验。
参考文献
总结
CLS(Cumulative Layout Shift) 是衡量页面视觉稳定性的核心指标,它反映了页面在加载过程中的布局偏移程度。布局偏移是指页面元素在加载或交互过程中意外移动,可能导致用户误操作或产生不良体验。优化 CLS 主要通过为动态内容预留空间、避免触发布局重排、使用动画时避免修改布局属性等方式,确保页面加载和用户交互过程中的稳定性。目标是使 CLS 值保持低于 0.1,以提供更流畅的用户体验。