Google在2020年推出了Core Web Vitals,作为衡量网站用户体验的核心指标。最近对公司的网站做了一轮Core Web Vitals性能优化,把LCP从4.2秒降到了1.5秒,FID从300ms降到了20ms,CLS从0.25降到了0.02。记录一下整个优化过程。
先说说背景。我们公司有一个内容网站,每天的访问量大概几十万PV。之前网站的性能一直不太好,打开速度慢,用户体验差,跳出率很高。Google在2020年5月的I/O大会上正式推出了Core Web Vitals,并且宣布从2021年开始,Core Web Vitals会作为搜索排名的因素之一。我们意识到,如果不优化网站性能,不仅用户体验差,还会影响SEO排名。
于是我牵头做了一轮网站性能优化,目标是把Core Web Vitals的三个核心指标(LCP、FID、CLS)都优化到Google的"良好"标准以内。经过大概两周的努力,我们达到了目标,LCP从4.2秒降到了1.5秒,FID从300ms降到了20ms,CLS从0.25降到了0.02,网站的跳出率下降了20%,平均停留时间增加了30%。
今天就把整个优化过程记录下来,从Core Web Vitals的概念、测量方法、到具体的优化手段,一次说清楚。
一、什么是Core Web Vitals
在说优化之前,先简单介绍一下什么是Core Web Vitals。
Core Web Vitals是Google提出的一组衡量网站用户体验的核心指标,包括三个指标:LCP(Largest Contentful Paint,最大内容绘制)、FID(First Input Delay,首次输入延迟)、CLS(Cumulative Layout Shift,累积布局偏移)。
这三个指标分别衡量了用户体验的三个方面:加载性能、交互响应性、视觉稳定性。
LCP(最大内容绘制):衡量页面的加载性能,指的是页面上最大的内容元素(比如图片、视频、大段文字)渲染完成的时间。Google的标准是:LCP在2.5秒以内为"良好",2.5秒到4秒为"需要改进",超过4秒为"较差"。
FID(首次输入延迟):衡量页面的交互响应性,指的是用户第一次和页面交互(比如点击按钮、点击链接)到浏览器真正开始处理这个交互的时间。FID反映的是主线程的繁忙程度,如果主线程被大量的JavaScript执行阻塞了,用户的交互就会被延迟。Google的标准是:FID在100毫秒以内为"良好",100毫秒到300毫秒为"需要改进",超过300毫秒为"较差"。
注意:FID在2024年已经被INP(Interaction to Next Paint,交互到下一次绘制)取代了,但在2020年的时候,FID还是Core Web Vitals的指标之一,所以这篇文章里还是用FID。
CLS(累积布局偏移):衡量页面的视觉稳定性,指的是页面在加载过程中,元素位置发生意外偏移的累积分数。比如,页面加载的时候,图片没有设置尺寸,图片加载完成后把下面的文字挤下去了,这就是布局偏移。CLS衡量的就是所有这些意外偏移的总和。Google的标准是:CLS在0.1以内为"良好",0.1到0.25为"需要改进",超过0.25为"较差"。
这三个指标合在一起,就是Core Web Vitals,它们从不同的维度衡量了用户访问网站时的真实体验。Google认为,一个好的网站,不仅要内容好,还要加载快、响应快、视觉稳定。
二、如何测量Core Web Vitals
优化的第一步是测量,只有知道了当前的指标,才能有针对性地优化。测量Core Web Vitals有几种方法:
第一种是实验室测量工具,比如Lighthouse、WebPageTest。这些工具可以在受控的环境下(比如固定的网络速度、固定的设备)测量网站的性能,给出详细的性能报告和优化建议。Lighthouse是Chrome DevTools内置的,可以直接在浏览器里运行,很方便。WebPageTest是一个在线工具,可以选择不同的地理位置、设备、网络速度来测试,功能更强大。
实验室测量的优点是可控、可重复,适合在开发阶段做性能测试和优化。缺点是它测量的是实验室环境下的性能,不一定能反映真实用户的体验,因为真实用户的设备、网络、环境千差万别。
第二种是真实用户测量(RUM,Real User Monitoring),比如Chrome User Experience Report(CrUX)、Google Search Console、以及一些第三方的RUM工具(比如New Relic、Datadog)。这些工具收集的是真实用户访问网站时的性能数据,能反映真实的用户体验。
CrUX是Google收集的Chrome用户的真实性能数据,可以通过PageSpeed Insights或者BigQuery查询。Google Search Console里也有Core Web Vitals的报告,展示网站在真实用户中的性能表现。
真实用户测量的优点是能反映真实的用户体验,数据更有说服力。缺点是数据是聚合的,不容易定位具体的问题,而且数据有延迟,不能实时反映优化的效果。
我的建议是,实验室测量和真实用户测量结合起来用。在开发和优化阶段,用Lighthouse等实验室工具来定位问题、验证优化效果;在优化完成后,用Search Console等真实用户数据来确认优化的效果。
我们这次优化,就是先用Lighthouse跑了一遍,发现LCP 4.2秒(较差)、FID 300ms(需要改进)、CLS 0.25(需要改进)。然后针对每个指标,分析原因,做优化,优化完之后再用Lighthouse验证,最后用Search Console的真实数据确认效果。
三、LCP优化:从4.2秒到1.5秒
先说说LCP的优化。LCP衡量的是最大内容元素的渲染时间,我们的网站LCP是4.2秒,主要的LCP元素是文章的封面图。
LCP慢的原因,一般有以下几个:服务器响应慢、资源加载慢、渲染阻塞、LCP元素本身加载慢。我们逐一分析,做了以下优化:
优化1:提升服务器响应速度(TTFB)
TTFB(Time To First Byte,首字节时间)是从用户发起请求到服务器返回第一个字节的时间,TTFB慢的话,后面所有的步骤都会被延迟。我们的网站TTFB大概是800ms,比较慢。
原因是我们用的是共享主机,服务器的性能一般,而且网站用的是WordPress,每次请求都要执行PHP、查询数据库,响应比较慢。
优化方法:
- 升级服务器,从共享主机换到了VPS,CPU和内存都提升了
- 安装了Redis对象缓存,把数据库查询结果缓存起来,减少数据库查询
- 开启了OPcache,缓存PHP的编译结果,减少PHP的解析和编译时间
- 优化了数据库,给常用的查询字段加了索引,清理了垃圾数据
优化之后,TTFB从800ms降到了200ms,效果很明显。
优化2:使用CDN加速静态资源
我们的网站有很多静态资源,比如图片、CSS、JavaScript,这些资源如果都从源服务器加载,速度会比较慢,尤其是对于离服务器远的用户。
我们接入了CDN(内容分发网络),把静态资源缓存到CDN的边缘节点上,用户访问的时候,从离他最近的边缘节点加载资源,速度快很多。
同时,我们还开启了CDN的图片优化功能,自动把图片转换成WebP格式,根据用户的设备自动调整图片尺寸,减少图片的体积。
优化之后,静态资源的加载速度提升了很多,尤其是图片的加载,体积减少了50%以上。
优化3:延迟加载非关键资源
页面上有很多资源不是首屏渲染必需的,比如页面底部的图片、评论区的脚本、统计代码等。这些资源可以延迟加载,等首屏渲染完成之后再加载,这样可以把带宽和CPU留给首屏的关键资源,加快LCP。
我们做了以下延迟加载:
- 图片懒加载:给非首屏的图片加上loading="lazy"属性,等图片滚动到视口附近的时候再加载
- JavaScript延迟加载:把非关键的JavaScript(比如统计代码、评论脚本、社交分享脚本)加上defer或者async属性,或者动态加载,不阻塞首屏渲染
- CSS拆分:把CSS拆成关键CSS和非关键CSS,关键CSS内联到HTML里,非关键CSS异步加载
优化之后,首屏需要加载的资源减少了很多,LCP元素能更快地加载和渲染。
优化4:优化LCP元素本身
我们的LCP元素是文章的封面图,这张图的加载速度直接决定了LCP。我们对这张图做了专门的优化:
- 预加载:在HTML的head里加上<link rel="preload" as="image" href="封面图URL">,让浏览器提前知道要加载这张图,优先加载
- 图片格式优化:把封面图转换成WebP格式,体积比JPG小30%到50%
- 图片尺寸优化:根据设备的屏幕尺寸,提供不同尺寸的图片,用srcset属性让浏览器选择合适的尺寸,避免在小屏幕上加载大图
- 压缩图片:用工具压缩图片,在保证画质的前提下,尽量减小体积
- 设置宽度和高度:给图片设置明确的width和height,避免布局偏移(这个对CLS也有帮助)
优化之后,封面图的加载速度大幅提升,LCP从4.2秒降到了1.5秒,达到了"良好"的标准。
四、FID优化:从300ms到20ms
再说说FID的优化。FID衡量的是首次输入延迟,反映的是主线程的繁忙程度。我们的网站FID是300ms,刚好在"需要改进"的边缘,主要原因是主线程被大量的JavaScript执行阻塞了。
FID慢的原因,一般是JavaScript太多、执行时间太长,或者有长任务(long task)阻塞了主线程。我们做了以下优化:
优化1:减少JavaScript的体积
我们的网站加载了很多JavaScript,包括WordPress的核心脚本、主题的脚本、各种插件的脚本,加起来有将近1MB,而且很多是不需要的。
我们做了以下精简:
- 禁用了不需要的插件:我们网站装了20多个插件,很多是没用的或者可以用代码替代的,禁用了10多个,减少了很多脚本加载
- 移除了不必要的脚本:比如jQuery migrate、wp-embed、emoji脚本等,这些对我们的网站来说是多余的
- 合并和压缩JavaScript:把多个小的JavaScript文件合并成一个,然后压缩,减少体积和请求数
- 代码分割:把JavaScript拆分成小的模块,只加载当前页面需要的代码,不需要的代码延迟加载
优化之后,JavaScript的体积从1MB降到了200KB,减少了80%。
优化2:优化JavaScript的执行
减少了体积之后,还要优化JavaScript的执行效率,避免长任务阻塞主线程。
我们做了以下优化:
- 把非关键的JavaScript放到页面底部,加上defer属性,让它在HTML解析完成之后再执行,不阻塞首屏渲染
- 把耗时的计算(比如数据处理、DOM操作)拆分成小的任务,用requestIdleCallback或者setTimeout来调度,避免单个任务执行时间太长
- 优化DOM操作,减少重排和重绘,比如用DocumentFragment批量插入元素,用classList代替直接修改style,用will-change提示浏览器优化
- 避免同步的Layout和Style计算,比如不要在循环里读取offsetWidth然后修改样式,这样会强制浏览器同步计算布局,影响性能
优化之后,主线程的长任务基本消失了,JavaScript的执行时间大幅减少。
优化3:使用Web Worker处理耗时任务
我们的网站有一些比较耗时的计算,比如搜索建议的生成、文章相关度的计算,这些计算如果放在主线程里执行,会阻塞主线程,影响FID。
我们把这些耗时的计算移到了Web Worker里,Web Worker在后台线程里执行,不会阻塞主线程。计算完成之后,通过postMessage把结果传回主线程,主线程再更新UI。
优化之后,这些耗时计算不再影响主线程了,FID进一步降低。
优化4:预加载关键JavaScript
对于首屏交互必需的JavaScript,我们用<link rel="preload" as="script">来预加载,让浏览器提前下载这些脚本,等需要执行的时候已经下载好了,减少等待时间。
注意,preload只是提前下载,不会提前执行,执行还是要等到脚本标签被解析的时候。所以,preload要配合defer或者把脚本放在底部来使用,才能达到最好的效果。
经过以上优化,我们的FID从300ms降到了20ms,远低于100ms的"良好"标准。
五、CLS优化:从0.25到0.02
最后说说CLS的优化。CLS衡量的是累积布局偏移,我们的网站CLS是0.25,在"需要改进"的范围。布局偏移主要发生在页面加载的时候,图片、广告、字体等元素加载完成后,把其他元素挤开了。
我们做了以下优化:
优化1:给图片和视频设置尺寸
这是最常见的布局偏移原因。图片和视频在加载完成之前,浏览器不知道它们的尺寸,如果没有设置width和height,浏览器会先按0尺寸渲染,等图片加载完成后再撑开,这样就会把下面的内容挤下去,造成布局偏移。
我们给所有的图片和视频都设置了明确的width和height属性,让浏览器在加载之前就知道它们的尺寸,提前预留好空间,这样图片加载完成后就不会造成布局偏移了。
对于响应式图片,我们用了aspect-ratio CSS属性,设置宽高比,这样不管图片显示多大,都能保持正确的比例,预留正确的空间。
优化2:给广告位预留空间
我们的网站有广告位,广告是通过JavaScript动态加载的,在广告加载完成之前,广告位的高度是0,等广告加载完成后,广告位撑开,把下面的内容挤下去,造成布局偏移。
我们给广告位设置了固定的高度或者最小高度,提前预留好空间,这样广告加载完成后就不会造成布局偏移了。如果广告的尺寸不固定,可以设置一个常见的尺寸,或者用占位符先占住位置。
优化3:优化字体加载
字体加载也会造成布局偏移。如果页面用了自定义字体,在字体加载完成之前,浏览器会先用系统字体渲染文字,等自定义字体加载完成后,再替换成自定义字体。如果自定义字体和系统字体的尺寸不一样,替换的时候文字的大小和位置就会变化,造成布局偏移,这就是所谓的"FOIT"(Flash of Invisible Text)或者"FOUT"(Flash of Unstyled Text)。
我们做了以下优化:
- 用font-display: swap,让浏览器先用系统字体渲染,自定义字体加载完成后再替换,这样至少文字不会消失
- 给自定义字体设置正确的size-adjust、ascent-override、descent-override等属性,让自定义字体和系统字体的尺寸尽量接近,减少替换时的布局偏移
- 用<link rel="preload">预加载关键字体,让字体更快加载完成,减少FOUT的时间
- 对于不是很重要的字体,可以考虑不用自定义字体,直接用系统字体,这样就不会有字体加载的问题了
优化4:避免在页面加载的时候动态插入内容
有些脚本会在页面加载的时候动态插入内容,比如公告条、cookie提示、订阅弹窗等,这些内容插入的时候,会把页面上已有的内容挤下去,造成布局偏移。
我们做了以下优化:
- 给这些动态内容预留空间,或者用固定定位(position: fixed),让它们覆盖在页面上面,不影响其他元素的布局
- 如果必须在文档流中插入,尽量在页面加载的早期就插入,不要等其他内容都渲染好了再插入,这样偏移的影响会小一些
- 对于可以延迟的内容(比如订阅弹窗),等页面加载完成、用户交互之后再显示,这样就不会影响首屏的布局稳定性了
优化5:用transform和opacity做动画
如果页面上有动画,尽量用transform和opacity来做,不要用top、left、width、height这些会影响布局的属性。因为transform和opacity不会触发重排,只会触发合成,不会影响其他元素的位置,也就不会造成布局偏移。而top、left这些属性会触发重排,动画过程中元素的位置变化可能会影响其他元素,造成布局偏移。
经过以上优化,我们的CLS从0.25降到了0.02,远低于0.1的"良好"标准。
六、优化效果总结
所有优化完成之后,我们重新用Lighthouse测试了一下,结果如下:
| 指标 | 优化前 | 优化后 | 变化 |
|---|---|---|---|
| LCP | 4.2秒 | 1.5秒 | 提升64% |
| FID | 300ms | 20ms | 提升93% |
| CLS | 0.25 | 0.02 | 提升92% |
| 页面总大小 | 3.2MB | 1.1MB | 减少66% |
| 请求数 | 85 | 32 | 减少62% |
三个Core Web Vitals指标都达到了Google的"良好"标准,Lighthouse的性能评分从35分提升到了95分。
除了性能指标的提升,网站的业务指标也有明显改善:
- 跳出率下降了20%
- 平均停留时间增加了30%
- 页面浏览量增加了15%
- 转化率提升了10%
一个月之后,我们在Google Search Console里看到,真实用户的Core Web Vitals数据也有了明显改善,大部分页面都达到了"良好"标准。而且,网站的搜索排名也有了一定的提升,自然流量增加了约10%。
七、一些经验和建议
最后,分享一些Core Web Vitals性能优化的经验和建议。
第一,先测量再优化。不要上来就改代码,先用Lighthouse等工具测量一下,看看当前的指标是多少,主要的问题在哪里,然后有针对性地优化。不同的网站,性能瓶颈可能不一样,有的是LCP慢,有的是FID慢,有的是CLS高,要根据具体情况来优化。
第二,关注真实用户数据。实验室数据很重要,但真实用户数据更重要,因为它反映的是真实用户的体验。要定期查看Search Console里的Core Web Vitals报告,看看真实用户的表现,发现问题及时优化。
第三,性能优化是一个持续的过程。不是优化一次就完事了,随着网站的迭代,新的功能、新的插件、新的代码都可能引入新的性能问题。要把性能监控纳入日常的开发流程中,每次发布新功能之前,都跑一下Lighthouse,看看性能有没有下降,发现问题及时解决。
第四,不要为了优化而优化。性能优化的目的是提升用户体验,不是为了追求Lighthouse的高分。有些优化可能会提升分数,但会影响用户体验或者开发效率,这时候就要权衡利弊,选择最合适的方案。
第五,关注新的指标和标准。Core Web Vitals的指标在不断演进,比如FID在2024年被INP取代了,未来可能还会有新的指标。要关注Google的官方动态,及时了解新的标准和最佳实践。
八、写在最后
Core Web Vitals是Google推出的衡量网站用户体验的核心指标,它不仅影响用户体验,还会影响SEO排名。对于任何一个网站来说,优化Core Web Vitals都是一件值得做的事情。
这次优化经历让我深刻体会到,性能优化不是什么高深的技术,更多的是细节的把控。给图片设置尺寸、延迟加载非关键资源、精简JavaScript、给广告位预留空间,这些都是很小的细节,但把这些细节都做好了,性能就能有质的飞跃。
当然,性能优化也不是一蹴而就的,需要持续的关注和投入。但只要我们把用户体验放在心上,把性能优化融入到日常的开发流程中,就一定能做出又快又好的网站。
希望我的这篇实战经验能对你有所帮助。如果有什么问题或者不同的看法,欢迎在评论区交流。
评论(0)
暂无评论,快来抢沙发~
评论功能仅对会员开放,请先登录
登录