各位靓仔靓女,晚上好!我是今晚的讲师,老码农一枚。今天咱聊聊前端性能优化里两个重要的指标:First Contentful Paint (FCP) 和 Largest Contentful Paint (LCP),以及优化它们的关键技术:Critical CSS。 保证讲得通俗易懂,干货满满,希望大家听完能有所收获。
开场白:性能,用户体验的基石
各位,咱们做前端的,说白了就是给用户提供服务的。用户体验好不好,直接关系到产品的生死存亡。你想啊,如果一个网站打开慢得像蜗牛爬,谁还有耐心等你?用户分分钟就跑去竞争对手那里了。而FCP和LCP,就是衡量用户体验的重要指标,直接影响用户的第一印象。
第一部分:FCP (First Contentful Paint) – 你的网站有多快“露脸”
1. 什么是FCP?
FCP,顾名思义,指的是浏览器首次渲染任何文本、图像、非白色canvas或SVG的时间点。简单来说,就是用户第一次看到页面内容的时间。这个时间越短,用户感觉你的网站加载越快。
2. 为什么FCP很重要?
想象一下,你打开一个网站,一片空白,啥也没有,你会不会觉得很焦虑?FCP就是用来衡量这种“焦虑”程度的。一个好的FCP能让用户知道“嘿,网站在加载了,不是死机了”,从而降低他们的焦虑感,提高用户留存率。
3. 如何测量FCP?
测量FCP的方法有很多,最常用的是通过浏览器的Performance API。
// 在浏览器控制台中运行
new PerformanceObserver((entryList) => {
for (const entry of entryList.getEntriesByName('first-contentful-paint')) {
console.log('FCP:', entry.startTime);
}
}).observe({ type: 'paint', buffered: true });
这段代码会在浏览器控制台中输出FCP的时间。也可以使用Lighthouse、PageSpeed Insights等工具来测量FCP。
4. FCP优化策略
-
减少HTTP请求:
-
合并文件: 将多个CSS和JavaScript文件合并成一个,减少HTTP请求的数量。可以使用Webpack、Parcel等打包工具来实现。
// webpack.config.js module.exports = { // ... optimization: { splitChunks: { cacheGroups: { vendor: { test: /[\/]node_modules[\/]/, name: 'vendors', chunks: 'all', }, }, }, }, };
-
使用CSS Sprites: 将多个小图标合并成一张大图,减少HTTP请求的数量。可以使用像
gulp-spritesmith
这样的工具。 -
Inline critical resources: 嵌入关键CSS到HTML中,避免额外的HTTP请求。这个我们稍后会详细讲到Critical CSS。
-
-
优化服务器响应时间 (TTFB):
- 使用CDN: 将静态资源分发到全球各地的CDN节点,让用户从离他们最近的节点获取资源。
- 优化后端代码: 检查数据库查询、缓存策略等,确保服务器能快速响应请求。
- 启用Gzip压缩: 压缩HTML、CSS、JavaScript等资源,减少传输体积。
在你的服务器配置里(比如Nginx):
gzip on; gzip_types text/plain text/css application/javascript application/x-javascript text/xml application/xml application/xml+rss image/svg+xml; gzip_comp_level 6; gzip_vary on; gzip_disable "msie6";
-
优化资源加载顺序:
- 优先加载关键资源: 将首屏需要的CSS和JavaScript放在
<head>
中,尽快加载。 - 延迟加载非关键资源: 使用
async
或defer
属性延迟加载非关键JavaScript文件。<script src="script.js" async></script> <script src="script.js" defer></script>
async
会异步加载脚本并在加载完成后立即执行,不阻塞HTML解析。
defer
会异步加载脚本,但会等到HTML解析完成后再执行,保证执行顺序。
- 优先加载关键资源: 将首屏需要的CSS和JavaScript放在
-
使用浏览器缓存:
- 设置正确的Cache-Control头: 告诉浏览器哪些资源可以缓存,以及缓存的时间。
Cache-Control: public, max-age=31536000
- 设置正确的Cache-Control头: 告诉浏览器哪些资源可以缓存,以及缓存的时间。
-
避免阻塞渲染的JavaScript和CSS:
- 移除无用的CSS和JavaScript: 减少不必要的代码,减少浏览器解析和执行的时间。
- Code Splitting: 使用Webpack等工具将代码分割成多个小块,按需加载。
第二部分:LCP (Largest Contentful Paint) – 你的网站有多快“画完”
1. 什么是LCP?
LCP,指的是在viewport中最大的可见元素完成渲染的时间点。这个元素可以是图像、视频、background-image
、块级文本元素等。简单来说,就是用户看到页面上最大的内容的时间。
2. 为什么LCP很重要?
LCP比FCP更贴近用户体验。一个好的FCP能让用户知道网站在加载,但如果LCP很慢,用户可能会觉得“等了半天,就加载了这么点东西”。LCP直接影响用户对页面加载速度的感知。
3. 如何测量LCP?
和FCP一样,可以使用Performance API来测量LCP。
new PerformanceObserver((entryList) => {
for (const entry of entryList.getEntries()) {
console.log('LCP:', entry.startTime, entry.url, entry.size);
}
}).observe({ type: 'largest-contentful-paint', buffered: true });
这段代码会在浏览器控制台中输出LCP的时间、URL和大小。同样也可以使用Lighthouse、PageSpeed Insights等工具来测量LCP。
4. LCP优化策略
-
优化服务器响应时间 (TTFB): 和FCP一样,TTFB是LCP的关键因素。
-
优化资源加载时间:
-
优化图片:
- 选择合适的图片格式: 使用WebP格式,它可以提供更好的压缩率和质量。
- 压缩图片: 使用工具如TinyPNG、ImageOptim等压缩图片,减小文件大小。
- 使用响应式图片: 根据用户的设备屏幕大小加载不同尺寸的图片。
<img srcset="small.jpg 480w, medium.jpg 800w, large.jpg 1200w" sizes="(max-width: 480px) 480px, (max-width: 800px) 800px, 1200px" src="large.jpg" alt="My Image">
- 使用CDN: 将图片分发到全球各地的CDN节点,让用户从离他们最近的节点获取图片。
-
优化视频:
- 压缩视频: 使用工具如FFmpeg等压缩视频,减小文件大小。
- 使用流媒体: 使用HLS、DASH等流媒体协议,根据用户的网络状况动态调整视频质量。
- 使用CDN: 将视频分发到全球各地的CDN节点,让用户从离他们最近的节点获取视频。
-
-
优化渲染阻塞资源:
- Critical CSS: 这个我们接下来会详细讲到。
- 预加载关键资源: 使用
<link rel="preload">
预加载LCP元素所需的资源。<link rel="preload" href="image.jpg" as="image">
-
避免客户端渲染:
- 使用服务端渲染 (SSR): 在服务器端渲染HTML,将完整的HTML发送给浏览器,避免客户端渲染的延迟。可以使用Next.js、Nuxt.js等框架来实现SSR。
- 预渲染 (Prerendering): 在构建时生成HTML,将静态HTML发送给浏览器。可以使用预渲染工具如
prerender-spa-plugin
。
第三部分:Critical CSS – 优先加载“骨架”
1. 什么是Critical CSS?
Critical CSS,也叫Above-the-Fold CSS,指的是渲染首屏内容所需的最小CSS集合。简单来说,就是让用户在第一时间看到页面“骨架”的CSS。
2. 为什么Critical CSS很重要?
如果没有Critical CSS,浏览器需要加载完整的CSS文件才能开始渲染页面。这会导致页面出现“白屏”现象,用户体验很差。有了Critical CSS,浏览器可以先加载Critical CSS,渲染出页面的“骨架”,然后再加载完整的CSS文件,从而提高用户的感知速度。
3. 如何提取Critical CSS?
提取Critical CSS的方法有很多,最常用的是使用工具。
- 在线工具: 像CriticalCSS.com这样的在线工具,可以输入URL,自动提取Critical CSS。
-
npm包: 有很多npm包可以用来提取Critical CSS,如
critical
、penthouse
等。以
critical
为例:npm install critical --save-dev
// 使用critical const critical = require('critical'); critical.generate({ inline: false, // 是否将critical CSS内联到HTML中 base: 'dist/', // 你的网站的根目录 src: 'index.html', // HTML文件路径 target: { css: 'critical.css', // 输出的critical CSS文件路径 html: 'index.html' // 修改后的HTML文件路径 }, minify: true, // 是否压缩CSS extract: false, // 是否提取所有CSS规则 width: 1300, // 屏幕宽度 height: 900 // 屏幕高度 }).then(output => { console.log("Critical CSS generated!"); }).catch(err => { console.error(err); });
4. 如何使用Critical CSS?
提取Critical CSS后,需要将它内联到HTML的<head>
中,并使用media="print"
或onload="this.removeAttribute('media');"
异步加载完整的CSS文件。
<head>
<style>
/* Critical CSS */
body {
font-family: sans-serif;
margin: 0;
}
/* ... 其他关键CSS ... */
</style>
<link rel="stylesheet" href="style.css" onload="this.removeAttribute('media');" media="print">
<noscript><link rel="stylesheet" href="style.css"></noscript>
</head>
onload="this.removeAttribute('media');"
: 这种方法会在完整的CSS文件加载完成后,将media
属性移除,从而应用CSS样式。<noscript><link rel="stylesheet" href="style.css"></noscript>
: 如果用户禁用了JavaScript,则会加载完整的CSS文件。
总结:优化FCP和LCP,打造极速体验
指标 | 含义 | 优化策略 |
---|---|---|
FCP | 浏览器首次渲染任何文本、图像、非白色canvas或SVG的时间点。 | 1. 减少HTTP请求 2. 优化服务器响应时间 (TTFB) 3. 优化资源加载顺序 4. 使用浏览器缓存 5. 避免阻塞渲染的JavaScript和CSS |
LCP | 在viewport中最大的可见元素完成渲染的时间点。 | 1. 优化服务器响应时间 (TTFB) 2. 优化资源加载时间 (图片/视频) 3. 优化渲染阻塞资源 (Critical CSS, 预加载) 4. 避免客户端渲染 (SSR, 预渲染) |
Critical CSS | 渲染首屏内容所需的最小CSS集合。 | 1. 使用工具提取Critical CSS 2. 将Critical CSS内联到HTML的<head> 中 3. 使用media="print" 或onload="this.removeAttribute('media');" 异步加载完整的CSS文件。 4. <noscript><link rel="stylesheet" href="style.css"></noscript> 防止JS禁用。 |
总而言之,优化FCP和LCP是一个系统工程,需要从服务器端到客户端进行全方位的优化。希望今天的分享能帮助大家更好地理解和优化FCP和LCP,打造极速的用户体验。
结束语:性能优化,永无止境
各位,性能优化是一个持续不断的过程,没有最好,只有更好。希望大家在实际项目中不断尝试、总结,找到最适合自己的优化方案。
今天的讲座就到这里,谢谢大家!如果大家有什么问题,欢迎提问。