性能与优化
Web 性能优化是现代前端开发的核心关注点。快速加载的页面不仅能提升用户体验,还能提高搜索引擎排名和转化率。本文档将介绍 HTML 层面的性能优化技术,包括资源加载策略、图片与字体优化、关键渲染路径优化等内容。
1. 资源加载优化
1.1 JavaScript 加载策略
1.1.1 <script> 标签的加载方式
默认情况下,<script> 标签会阻塞 HTML 解析,导致页面渲染延迟。
无属性(阻塞渲染):
1
| <script src="app.js"></script>
|
使用 defer 属性(延迟执行):
1
| <script defer src="app.js"></script>
|
- 立即下载,但不阻塞 HTML 解析
- 在 DOM 解析完成后,按顺序执行
- 适用于需要操作 DOM 的脚本
- 多个
defer 脚本按顺序执行
使用 async 属性(异步执行):
1
| <script async src="analytics.js"></script>
|
- 立即下载,不阻塞 HTML 解析
- 下载完成后立即执行(可能中断 HTML 解析)
- 执行顺序不确定
- 适用于独立的第三方脚本(如分析工具)
1.1.2 defer vs async 对比
| 特性 |
无属性 |
defer |
async |
| 阻塞 HTML 解析 |
✅ 是 |
❌ 否 |
❌ 否 |
| 执行时机 |
立即 |
DOM 解析后 |
下载后立即 |
| 执行顺序 |
按顺序 |
按顺序 |
不确定 |
| 适用场景 |
必要脚本 |
依赖 DOM 的脚本 |
独立脚本 |
推荐实践:
1 2 3 4 5
| <script defer src="main.js"></script>
<script async src="https://www.google-analytics.com/analytics.js"></script>
|
1.2 预加载(Preload)
preload 用于提前加载当前页面必需的关键资源。
1.2.1 基本语法
1 2 3 4
| <link rel="preload" href="font.woff2" as="font" type="font/woff2" crossorigin> <link rel="preload" href="critical.css" as="style"> <link rel="preload" href="hero-image.jpg" as="image"> <link rel="preload" href="app.js" as="script">
|
1.2.2 as 属性值
| as 值 |
说明 |
示例 |
script |
JavaScript 文件 |
app.js |
style |
CSS 样式表 |
main.css |
image |
图片资源 |
hero.jpg |
font |
字体文件 |
font.woff2 |
audio |
音频文件 |
sound.mp3 |
video |
视频文件 |
video.mp4 |
fetch |
Fetch/XMLHttpRequest |
API 数据 |
document |
HTML 文档 |
page.html |
1.2.3 预加载关键资源示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| <head> <link rel="preload" href="fonts/main.woff2" as="font" type="font/woff2" crossorigin> <link rel="preload" href="styles/critical.css" as="style"> <link rel="preload" href="images/hero.jpg" as="image"> <link rel="preload" href="js/main.js" as="script"> </head>
|
注意事项:
- 仅预加载当前页面必需的关键资源
- 字体文件必须设置
crossorigin 属性
- 避免预加载过多资源,导致带宽浪费
1.3 预获取(Prefetch)
prefetch 用于在浏览器空闲时预加载用户可能访问的下一个页面的资源。
1.3.1 基本语法
1 2 3
| <link rel="prefetch" href="next-page.html"> <link rel="prefetch" href="next-page.js"> <link rel="prefetch" href="next-page.css">
|
1.3.2 使用场景
1 2 3 4 5 6 7 8 9
| <link rel="prefetch" href="/products/page-2.html">
<link rel="prefetch" href="/js/product-detail.js">
<link rel="dns-prefetch" href="https://api.example.com"> <link rel="preconnect" href="https://fonts.googleapis.com">
|
prefetch vs preload:
| 特性 |
preload |
prefetch |
| 优先级 |
高 |
低 |
| 时机 |
立即 |
浏览器空闲时 |
| 用途 |
当前页关键资源 |
下一个页面资源 |
| 带宽 |
占用当前带宽 |
不占用当前带宽 |
1.4 预连接(Preconnect)
preconnect 用于提前建立与第三方域名的连接,包括 DNS 解析、TCP 握手和 TLS 协商。
1 2 3 4 5 6 7 8 9
| <link rel="preconnect" href="https://fonts.googleapis.com"> <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link rel="preconnect" href="https://api.example.com">
<link rel="dns-prefetch" href="https://cdn.example.com">
|
使用场景:
- 第三方字体服务
- CDN 资源
- API 端点
- 社交媒体插件
1.5 其他资源提示
1 2 3 4 5
| <link rel="prerender" href="https://example.com/next-page.html">
<link rel="modulepreload" href="app.js">
|
2. 图片与字体优化
2.1 图片优化
2.1.1 图片格式选择
| 格式 |
特点 |
适用场景 |
| JPEG |
有损压缩,文件小 |
照片、复杂图像 |
| PNG |
无损压缩,支持透明 |
图标、简单图形 |
| WebP |
现代格式,压缩比高 |
通用(需兼容性处理) |
| AVIF |
最新格式,压缩比极高 |
现代浏览器 |
| SVG |
矢量图,无损缩放 |
图标、简单图形 |
| GIF |
支持动画 |
简单动画 |
2.1.2 响应式图片
**使用 srcset 和 sizes**:
1 2 3 4 5 6 7 8 9
| <img srcset="image-320w.jpg 320w, image-640w.jpg 640w, image-1280w.jpg 1280w" sizes="(max-width: 640px) 100vw, (max-width: 1280px) 50vw, 1280px" src="image-640w.jpg" alt="响应式图片">
|
使用 <picture> 元素(格式选择):
1 2 3 4 5 6 7
| <picture> <source srcset="image.avif" type="image/avif"> <source srcset="image.webp" type="image/webp"> <img src="image.jpg" alt="描述"> </picture>
|
结合响应式和格式选择:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| <picture> <source media="(max-width: 640px)" srcset="small.avif 1x, small-2x.avif 2x" type="image/avif"> <source media="(max-width: 640px)" srcset="small.webp 1x, small-2x.webp 2x" type="image/webp"> <source media="(max-width: 640px)" srcset="small.jpg 1x, small-2x.jpg 2x"> <source srcset="large.avif 1x, large-2x.avif 2x" type="image/avif"> <source srcset="large.webp 1x, large-2x.webp 2x" type="image/webp"> <img src="large.jpg" srcset="large.jpg 1x, large-2x.jpg 2x" alt="响应式图片"> </picture>
|
2.1.3 懒加载(Lazy Loading)
原生懒加载(现代浏览器):
1
| <img src="image.jpg" alt="描述" loading="lazy">
|
传统方法(使用 Intersection Observer):
1 2 3 4 5
| <img data-src="image.jpg" src="placeholder.jpg" alt="描述" class="lazy-load">
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| document.addEventListener('DOMContentLoaded', () => { const images = document.querySelectorAll('.lazy-load'); const imageObserver = new IntersectionObserver((entries, observer) => { entries.forEach(entry => { if (entry.isIntersecting) { const img = entry.target; img.src = img.dataset.src; img.classList.remove('lazy-load'); observer.unobserve(img); } }); }); images.forEach(img => imageObserver.observe(img)); });
|
2.1.4 图片优化最佳实践
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| <picture> <source srcset="hero.avif" type="image/avif"> <source srcset="hero.webp" type="image/webp"> <img src="hero.jpg" alt="Hero 图片"> </picture>
<img srcset="thumbnail.jpg 150w, large.jpg 800w" sizes="(max-width: 600px) 150px, 800px" src="thumbnail.jpg" alt="描述" loading="lazy">
<img src="image.jpg" alt="描述" loading="lazy" width="800" height="600">
<style> .blur-load { filter: blur(10px); transition: filter 0.3s; } .blur-load.loaded { filter: blur(0); } </style>
|
2.2 字体优化
2.2.1 字体加载策略
**关键字体使用 preload**:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| <head> <link rel="preload" href="fonts/main-bold.woff2" as="font" type="font/woff2" crossorigin> <style> @font-face { font-family: 'Main'; src: url('fonts/main-bold.woff2') format('woff2'); font-weight: 700; font-display: swap; } </style> </head>
|
字体显示策略(font-display):
| 值 |
行为 |
适用场景 |
auto |
浏览器默认 |
不推荐 |
block |
阻塞 3s,显示回退字体 |
品牌字体 |
swap |
立即显示回退字体 |
推荐 |
fallback |
阻塞 100ms,3s 超时后放弃 |
非关键字体 |
optional |
阻塞 100ms,不下载则放弃 |
装饰性字体 |
推荐配置:
1 2 3 4 5 6 7 8 9 10 11
| @font-face { font-family: 'CustomFont'; src: url('font.woff2') format('woff2'); font-weight: 400; font-style: normal; font-display: swap; }
body { font-family: 'CustomFont', 'Arial', sans-serif; }
|
2.2.2 字体子集化(Subsetting)
减少字体文件大小,只包含需要的字符。
1 2
| <link href="https://fonts.googleapis.com/css2?family=Roboto&text=Hello" rel="stylesheet">
|
2.2.3 字体优化最佳实践
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| <head> <link rel="preconnect" href="https://fonts.googleapis.com"> <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> <link rel="preload" href="fonts/roboto-bold.woff2" as="font" type="font/woff2" crossorigin> <link href="https://fonts.googleapis.com/css2?family=Roboto:wght@400;700&display=swap" rel="stylesheet"> <style> @font-face { font-family: 'Roboto'; src: url('fonts/roboto-regular.woff2') format('woff2'); font-weight: 400; font-display: swap; } @font-face { font-family: 'Roboto'; src: url('fonts/roboto-bold.woff2') format('woff2'); font-weight: 700; font-display: swap; } </style> </head>
|
3. 关键渲染路径(Critical Rendering Path)与阻塞点
3.1 关键渲染路径概述
关键渲染路径(CRP)是从接收 HTML、CSS 和 JavaScript 到渲染出可视化内容的过程。
渲染步骤:
- DOM 构建:解析 HTML 创建 DOM 树
- CSSOM 构建:解析 CSS 创建 CSSOM 树
- 渲染树构建:合并 DOM 和 CSSOM
- 布局(Layout):计算元素位置和大小
- 绘制(Paint):填充像素
- 合成(Composite):图层合成
3.2 渲染阻塞资源
3.2.1 CSS 阻塞渲染
默认行为:
<link> 标签会阻塞渲染
- CSS 必须完全下载并解析后才能渲染
优化方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| <style> body { margin: 0; } .header { ... } .hero { ... } </style>
<link rel="stylesheet" href="print.css" media="print"> <link rel="stylesheet" href="large.css" media="(min-width: 800px)">
<link rel="preload" href="non-critical.css" as="style" onload="this.onload=null;this.rel='stylesheet'"> <noscript><link rel="stylesheet" href="non-critical.css"></noscript>
|
3.2.2 JavaScript 阻塞渲染
默认行为:
<script> 会阻塞 HTML 解析
- 可能阻塞 CSSOM 构建
优化方法:
1 2 3 4 5 6 7 8 9 10 11
| <script defer src="main.js"></script>
<script async src="analytics.js"></script>
<script> </script> </body>
|
3.3 优化关键渲染路径
3.3.1 优化 HTML
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| <!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <style> body { margin: 0; font-family: Arial; } .header { ... } .hero { ... } </style> <link rel="preload" href="fonts/main.woff2" as="font" type="font/woff2" crossorigin> <link rel="preload" href="hero.jpg" as="image"> <link rel="preload" href="styles/main.css" as="style" onload="this.onload=null;this.rel='stylesheet'"> </head> <body> <header class="header">...</header> <main class="hero">...</main> <section class="content">...</section> <script defer src="main.js"></script> </body> </html>
|
3.3.2 关键资源优先级
识别关键资源:
- 首屏可见内容
- 关键字体
- 首屏图片
- 关键 JavaScript(如交互逻辑)
优化策略:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| <head> <style> </style> <link rel="preload" href="font.woff2" as="font" crossorigin> <link rel="preload" href="hero.jpg" as="image"> <link rel="preload" href="non-critical.css" as="style" onload="this.onload=null;this.rel='stylesheet'"> </head>
|
3.4 性能指标
3.4.1 关键性能指标(Web Vitals)
| 指标 |
说明 |
目标值 |
| FCP (First Contentful Paint) |
首次内容绘制 |
< 1.8s |
| LCP (Largest Contentful Paint) |
最大内容绘制 |
< 2.5s |
| FID (First Input Delay) |
首次输入延迟 |
< 100ms |
| CLS (Cumulative Layout Shift) |
累积布局偏移 |
< 0.1 |
| TTI (Time to Interactive) |
可交互时间 |
< 3.8s |
3.4.2 优化检查清单
HTML 优化:
- ✅ 最小化 HTML 大小
- ✅ 减少 DOM 深度
- ✅ 延迟加载非关键内容
- ✅ 使用语义化 HTML
CSS 优化:
- ✅ 内联关键 CSS
- ✅ 避免
@import
- ✅ 移除未使用的 CSS
- ✅ 使用媒体查询延迟加载
JavaScript 优化:
- ✅ 使用
defer 或 async
- ✅ 代码分割和懒加载
- ✅ 最小化 JavaScript 大小
- ✅ 避免长时间运行的脚本
资源优化:
- ✅ 压缩图片
- ✅ 使用现代图片格式
- ✅ 优化字体加载
- ✅ 启用 Gzip/Brotli 压缩
3.5 实践示例
优化的 HTML 页面:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66
| <!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>优化的页面</title> <style> * { box-sizing: border-box; margin: 0; padding: 0; } body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; line-height: 1.6; } .header { background: #333; color: #fff; padding: 1rem; } .hero { padding: 2rem; text-align: center; } </style> <link rel="preconnect" href="https://fonts.googleapis.com"> <link rel="preload" href="fonts/main.woff2" as="font" type="font/woff2" crossorigin> <link rel="preload" href="images/hero.jpg" as="image"> <link rel="preload" href="styles/non-critical.css" as="style" onload="this.onload=null;this.rel='stylesheet'"> <noscript><link rel="stylesheet" href="styles/non-critical.css"></noscript> </head> <body> <header class="header"> <h1>网站标题</h1> </header> <main class="hero"> <picture> <source srcset="images/hero.avif" type="image/avif"> <source srcset="images/hero.webp" type="image/webp"> <img src="images/hero.jpg" alt="Hero" loading="eager"> </picture> <h2>欢迎访问</h2> </main> <section class="content"> </section> <script defer src="js/main.js"></script> <script async src="https://www.google-analytics.com/analytics.js"></script> </body> </html>
|
4. 总结
HTML 层面的性能优化要点:
资源加载:
- 使用
defer/async 优化脚本加载
- 使用
preload 预加载关键资源
- 使用
prefetch 预取下一页面资源
- 使用
preconnect 提前建立连接
图片优化:
- 选择合适格式(WebP、AVIF)
- 使用响应式图片
- 实施懒加载
- 提供占位符
字体优化:
- 预加载关键字体
- 使用
font-display: swap
- 提供回退字体
- 考虑字体子集化
关键渲染路径:
- 内联关键 CSS
- 延迟非关键资源
- 优化资源加载顺序
- 减少渲染阻塞
通过合理运用这些技术,可以显著提升页面的加载速度和用户体验。