🧭 系列目标:100 篇
✅ 已完成:1 篇
📍 当前篇章:Day 02 - 资源加载优化:图片、CSS、字体、JS 全面实战
网站首屏加载慢、白屏时间长、布局跳动频繁……这些都可能与你资源加载的方式息息相关。本文将以结构化视角,深入剖析前端中图片、CSS、字体和 JS 的资源加载优化策略,并提供相关方法。
1. 图片资源优化
在现代 Web 应用中,图片往往占据页面资源体积的 60%~80%。如果图片加载没做好,会出现:
-
首屏加载慢,影响用户体验和转化
-
滚动卡顿,尤其是瀑布流或大图浏览页
-
页面跳动,尤其在图片加载完成前布局被打乱
-
数据流量消耗大,影响移动端用户成本
所以,图片优化不仅是节省流量,而是用户体验的保障。
1.1 使用现代图片格式(WebP、AVIF)
<picture>
<source srcset="banner.webp" type="image/webp">
<img src="banner.jpg" alt="Banner 图像">
</picture>
📌 优点:浏览器支持自动选择最佳格式;提升图片压缩比,减少体积。
1.2 懒加载(Lazy Load)
原生方案:
<img src="image.jpg" loading="lazy" alt="惰性加载图像">
IntersectionObserver 示例(兼容更旧浏览器):
手动监听滚动 + IntersectionObserver,实现自定义懒加载
const observer = new IntersectionObserver(entries => {
entries.forEach(entry => {
if (entry.isIntersecting) {
const img = entry.target;
img.src = img.dataset.src;
observer.unobserve(img);
}
});
});
document.querySelectorAll('img[data-src]').forEach(img => observer.observe(img));
1.3 使用 LQIP 占位(Base64 小图)
低质量图(LQIP)嵌入可避免图片加载前的跳动:
<img
src="data:image/jpeg;base64,/9j/4AAQSkZJ..."
data-src="highres.jpg"
width="600"
height="400"
class="lazy"
/>
或者在背景图中使用:
.skeleton {
background-image: url('data:image/webp;base64,UklGRh...');
background-size: cover;
}
JavaScript 懒加载后替换高清图:
const img = document.querySelector('.lazy')
img.src = img.dataset.src
1.4 使用 Web Worker 解耦图像处理逻辑
对于图像缩放、滤镜、调整亮度等高开销计算:
主线程
const worker = new Worker('resize-worker.js')
worker.postMessage({ image, width: 300 })
worker.onmessage = (e) => updateCanvas(e.data)
Worker 文件(resize-worker.js)
self.onmessage = (e) => {
const { image, width } = e.data
const resized = resizeImage(image, width)
self.postMessage(resized)
}
可显著降低主线程卡顿,提升复杂图像处理体验。
1.5 CDN 加速图片加载
-
使用 CDN 缓存图片,靠近用户的节点提供更快响应。
-
推荐服务:七牛、阿里云 OSS、Cloudflare Images。
1.6 响应式图片加载(Responsive Images)
-
为不同屏幕密度和尺寸提供不同尺寸图片:

2. CSS 加载优化
传统做法中,所有 CSS 文件通过 <link> 引入,浏览器必须下载、解析完 CSS 才开始渲染页面。这带来了两个问题:
-
⏳ 阻塞渲染:CSS 是渲染阻塞资源,没加载完,页面白屏。
-
🧱 加载冗余:首屏渲染只用到了其中一小部分样式,其它全是浪费。
2.1 Critical CSS 提取(首屏样式内联)
<style>
.header { height: 60px; background: #fff; }
.hero { display: flex; height: 100vh; align-items: center; }
</style>
主样式异步加载,避免阻塞渲染:
<link rel="preload" href="main.css" as="style" onload="this.onload=null;this.rel='stylesheet'">
<noscript><link rel="stylesheet" href="main.css"></noscript>
工具推荐:
-
critters:适合 React/Vite -
penthouse:适合自定义构建流程
2.2 路由级别样式(Route-specific CSS)
针对 SPA,将样式随页面组件懒加载:
// Vue 路由懒加载
component: () => import('@/views/Home.vue')
// Vite + Vue3 自动提取局部 CSS
这样每个路由只加载自身所需样式,减小初始 CSS 体积。
3. 字体加载优化
3.1 字体渲染优化:避免 FOIT(文字不可见)
@font-face {
font-family: 'MyFont';
src: url('/fonts/myfont.woff2') format('woff2');
font-display: swap;
}
📌 使用 font-display: swap 可实现 FOUT(字体替换时闪烁),确保首屏内容不空白。
3.2 字体子集化(子集裁剪)
只保留使用到的中文字符:
npx fontmin myfont.ttf > myfont.min.ttf
或使用自动工具:
npx glyphhanger --subset=/index.html --formats=woff2 --LATIN
4. JavaScript 加载优化
4.1 使用 defer 和 async
<script src="/app.js" defer></script>
<script src="/analytics.js" async></script>
-
defer:页面解析完才执行,适用于主逻辑脚本 -
async:加载即执行,适用于无依赖脚本如监控、广告
4.2 动态导入(Code Splitting)
const Chart = () => import(/* webpackChunkName: "chart" */ './Chart.vue')
📌 搭配路由懒加载效果显著,减少首页包体积。
4.3 Tree Shaking & Scope Hoisting
确保使用 ES Module 并启用 sideEffects: false:
// package.json
{
"sideEffects": false
}
4.4 SSR 优化 JS 首屏加载体验
- Vue(Nuxt)、React(Next)通过 SSR 缓解 JS 渲染白屏。
4.5 请求合并与缓存优化
-
利用 HTTP/2 多路复用 +
keep-alive合理合并请求。 -
设置合适的
cache-control与etag提升重复访问性能。
5. 预加载技术进阶
5.1 Preload 当前页核心资源
<link rel="preload" href="font.woff2" as="font" type="font/woff2" crossorigin="anonymous">
<link rel="preload" href="home.css" as="style">
5.2 Prefetch 后续可能资源
<link rel="prefetch" href="next-page.js">
📌 适用于用户空闲时加载“下一个页面”资源。
6. 总结与工具推荐
✅ 对照表
🔧 工程化自动实现建议
🧠 小结
前端资源加载优化是影响页面性能的基石之一。只有将资源按需、分阶段、有策略地加载,才能做到“快如闪电、稳如老狗”的体验。别忘了,优化不仅仅是压缩体积,更是优化加载路径与阻塞点。