Bootstrap: 性能优化与构建部署
最后更新:2026-08-26
1. 本课导读
(1) 前置知识
- Bootstrap 暗色模式与主题切换(Lesson 21)
- 前端性能指标基本概念
- HTML 和 CSS 资源加载机制
(2) 🎯 你将学到
- 分析 Bootstrap 项目资源体积与加载性能
- 使用 PurgeCSS 去除未使用的 CSS
- 优化 JavaScript 按需加载与延迟加载
- 掌握图片优化和 CDN 部署最佳实践
- 配置完整的生产构建与部署流程
(3) 痛点
Alice 完成了她的 Bootstrap 作品集网站,但页面加载需要 3 秒——用户可能还没等到页面加载就已经离开了,Lighthouse 评分也很低。
(4) 解法
一个页面做好只是第一步,让它加载快、体验好才是最终目标。本课汇集 Bootstrap 项目的性能优化和构建部署最佳实践:CSS 压缩、JS 按需加载、图片优化、CDN 预热——通过优化减少到 0.8 秒。
理解方式: 性能优化 = 给网站"减肥"——去掉不需要的代码、压缩资源、让浏览器缓存结果,让页面在 1 秒内完成加载。
(5) 收益
Alice 的 Bootstrap 作品集网站从 3 秒优化到 0.8 秒,Lighthouse 评分大幅提升,用户访问体验显著改善,网站转化率也随之提高。
2. Bootstrap 体积分析
| 资源 | 未压缩 | Gzip 压缩后 | 备注 |
|---|---|---|---|
bootstrap.min.css |
~250KB | ~28KB | 完整框架 |
bootstrap.bundle.min.js |
~205KB | ~22KB | 含 Popper |
bootstrap.min.js |
~170KB | ~19KB | 不含 Popper |
| Bootstrap Icons CSS | ~220KB | ~25KB | 2000+ 图标 |
关键结论: 完整 Bootstrap 的 CSS + JS 压缩后约 50KB,对现代网络来说很小。真正影响性能的是图片、字体和第三方脚本。
▶ 示例:优化前 vs 优化后
graph LR
subgraph "Before optimization (3s)"
A1[HTML] --> B1[Full Bootstrap CSS]
B1 --> C1[Full Bootstrap JS]
C1 --> D1[Unoptimized images]
D1 --> E1[Google Fonts CSS]
E1 --> F1[3s load time]
end
subgraph "After optimization (0.8s)"
A2[HTML] --> B2[Purged CSS ~30KB]
B2 --> C2[Lazy loaded images]
C2 --> D2[Deferred JS]
D2 --> E2[CDN cache warm]
E2 --> F2[0.8s load time]
end
输出: Bootstrap 5.3 样式生效的组件效果(如按钮、卡片、轮播、折叠等),页面默认采用 Bootstrap 默认主题(亮色)和响应式网格。
3. CSS 优化
(1) 按需编译(Sass)
// 只导入用到的模块
@import "bootstrap/scss/functions";
@import "bootstrap/scss/variables";
@import "bootstrap/scss/mixins";
@import "bootstrap/scss/root";
@import "bootstrap/scss/reboot";
@import "bootstrap/scss/type";
@import "bootstrap/scss/grid";
@import "bootstrap/scss/buttons";
@import "bootstrap/scss/card";
@import "bootstrap/scss/navbar";
@import "bootstrap/scss/forms";
@import "bootstrap/scss/utilities";
@import "bootstrap/scss/utilities/api";
输出: Bootstrap 5.3 样式生效的组件效果(如按钮、卡片、轮播、折叠等),页面默认采用 Bootstrap 默认主题(亮色)和响应式网格。
(2) PurgeCSS 去冗余
PurgeCSS 能分析 HTML/JS 中实际使用的 class,删除未使用的 CSS:
npm install -D purgecss
// purgecss.config.js
module.exports = {
content: ['./**/*.html', './**/*.js'],
css: ['./dist/style.css'],
safelist: ['show', 'active', 'fade', 'collapse', 'modal-open']
}
输出: Bootstrap 5.3 样式生效的组件效果(如按钮、卡片、轮播、折叠等),页面默认采用 Bootstrap 默认主题(亮色)和响应式网格。
npx purgecss --config purgecss.config.js --output dist/style.min.css
(3) CDN 使用压缩版
<!-- Always use .min.css / .min.js in production -->
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet">
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
输出: Bootstrap 5.3 样式生效的组件效果(如按钮、卡片、轮播、折叠等),页面默认采用 Bootstrap 默认主题(亮色)和响应式网格。
4. JavaScript 优化
(1) 按需引入组件
// 只导入需要的 JS 组件
import Alert from 'bootstrap/js/dist/alert'
import Button from 'bootstrap/js/dist/button'
import Carousel from 'bootstrap/js/dist/carousel'
import Collapse from 'bootstrap/js/dist/collapse'
import Dropdown from 'bootstrap/js/dist/dropdown'
import Modal from 'bootstrap/js/dist/modal'
import Offcanvas from 'bootstrap/js/dist/offcanvas'
// Initialize all tooltips
document.querySelectorAll('[data-bs-toggle="tooltip"]')
.forEach(el => new bootstrap.Tooltip(el))
输出: Bootstrap 5.3 样式生效的组件效果(如按钮、卡片、轮播、折叠等),页面默认采用 Bootstrap 默认主题(亮色)和响应式网格。
(2) 延迟加载非关键 JS
<!-- Defer non-critical JS -->
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js" defer></script>
输出: Bootstrap 5.3 样式生效的组件效果(如按钮、卡片、轮播、折叠等),页面默认采用 Bootstrap 默认主题(亮色)和响应式网格。
(3) 图标按需引入
<!-- 如果用较少图标,直接用内联 SVG 替代图标字体 -->
<svg class="bi" width="16" height="16" fill="currentColor">
<use href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/bootstrap-icons.svg#house"/>
</svg>
<!-- 或者下载所需 SVG 到本地,避免 CDN 请求 -->
输出: Bootstrap 5.3 样式生效的组件效果(如按钮、卡片、轮播、折叠等),页面默认采用 Bootstrap 默认主题(亮色)和响应式网格。
5. 图片优化
<!-- Always use width + height to prevent layout shift -->
<img src="photo.webp" width="800" height="450" class="img-fluid" alt="Photo"
loading="lazy">
<!-- Use modern formats -->
<picture>
<source srcset="photo.avif" type="image/avif">
<source srcset="photo.webp" type="image/webp">
<img src="photo.jpg" class="img-fluid" alt="Photo">
</picture>
输出: Bootstrap 5.3 样式生效的组件效果(如按钮、卡片、轮播、折叠等),页面默认采用 Bootstrap 默认主题(亮色)和响应式网格。
6. 构建与部署
(1) 生产构建流程
// package.json
{
"scripts": {
"dev": "sass scss/custom.scss:dist/style.css --watch",
"build:css": "sass scss/custom.scss:dist/style.css --style compressed",
"build:purge": "purgecss --config purgecss.config.js --output dist/style.min.css",
"build": "npm run build:css && npm run build:purge",
"serve": "npx live-server --port=3000"
}
}
npm run build # Compile + purge
npm run serve # Local dev server
(2) 部署清单
| 项目 | 检查项 | 工具 |
|---|---|---|
| CSS | 已压缩、已 Purge、Critical CSS 内联 | PurgeCSS, Critical |
| JS | 已压缩、按需加载、defer | terser, webpack |
| 图片 | 已压缩、webp/avif、lazy loading | sharp, squoosh |
| 字体 | 预加载、font-display: swap | @font-face |
| 缓存 | CDN 缓存、ETag、Cache-Control | Cloudflare, Nginx |
| 分析 | Lighthouse score >= 90 | Lighthouse |
(3) Lighthouse 目标
| 指标 | 目标 |
|---|---|
| First Contentful Paint | < 1.5s |
| Largest Contentful Paint | < 2.5s |
| Total Blocking Time | < 200ms |
| Cumulative Layout Shift | < 0.1 |
| Speed Index | < 3.0s |
7. Bootstrap vs Tailwind 选型回顾
| 维度 | Bootstrap | Tailwind CSS |
|---|---|---|
| 学习成本 | ⭐⭐⭐ | ⭐⭐⭐⭐⭐ |
| 开发速度 | 快(组件即用) | 中(需组合 utility) |
| 文件体积 | 28KB gzip(完整) | 按需编译,通常 < 10KB |
| 定制能力 | 中(Sass 变量) | 高(设计系统) |
| 组件生态 | 70+ 内置 | 无(需 Headless UI) |
| 升级成本 | 低(语义化 class) | 中(class 变动) |
| 适合项目 | 后台、MVP、中小企业站 | 设计系统、品牌定制 |
8. 优化实战示例
▶ 示例:PurgeCSS 配置优化
// purgecss.config.js — Full production configuration
module.exports = {
content: [
'./src/**/*.html',
'./src/**/*.js',
'./src/**/*.php',
],
css: [
'./dist/style.css',
'./node_modules/bootstrap-icons/font/bootstrap-icons.css',
],
safelist: {
standard: [
// Bootstrap dynamic classes
/^bs-/, // All Bootstrap CSS variables
/^data-bs-/, // All data attributes
'active', 'show', 'fade', 'collapsing',
'modal-open', 'modal-backdrop',
'carousel-item-start', 'carousel-item-end',
'tooltip', 'popover', 'toast',
/^btn-/, // Button variant classes
/^bg-/, // Background classes
/^text-/, // Text color classes
/^border-/, // Border classes
/^alert-/, // Alert variants
/^badge-/, // Badge variants
],
deep: [
/^theme$/,
],
greedy: [
/dark/,
],
},
blocklist: [
/^bi-/, // Optionally remove unused BI icons
],
variables: true,
};
// Run: npx purgecss --config purgecss.config.js --output dist/style.purged.css
输出: Bootstrap 5.3 样式生效的组件效果(如按钮、卡片、轮播、折叠等),页面默认采用 Bootstrap 默认主题(亮色)和响应式网格。
// package.json scripts for optimized build
{
"scripts": {
"dev": "sass scss/custom.scss dist/style.css --watch",
"build:css": "sass scss/custom.scss dist/style.css --style compressed",
"build:purge": "purgecss --config purgecss.config.js --output dist/style.purged.css",
"build:copy": "cp dist/style.purged.css dist/style.min.css",
"build": "npm run build:css && npm run build:purge && npm run build:copy",
"build:all": "npm run build && npx terser dist/script.js -o dist/script.min.js",
"serve": "npx live-server --port=3000 --no-browser"
}
}
▶ 示例:Lighthouse 优化清单
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<!-- SEO Meta -->
<title>Optimized Bootstrap Page</title>
<meta name="description" content="Lighthouse score 95+ page built with Bootstrap.">
<!-- Preconnect to CDN -->
<link rel="preconnect" href="https://cdn.jsdelivr.net">
<link rel="dns-prefetch" href="https://cdn.jsdelivr.net">
<!-- Critical CSS inline (load first) -->
<style>
/* Minimal critical CSS for above-the-fold content */
.hero { background: #0d6efd; color: #fff; padding: 4rem 0; }
.container { max-width: 1140px; margin: 0 auto; padding: 0 1rem; }
@media (max-width: 768px) { .hero { padding: 2rem 0; } }
</style>
<!-- Non-critical CSS (deferred) -->
<link rel="preload" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" as="style" onload="this.onload=null;this.rel='stylesheet'">
<noscript><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css"></noscript>
<!-- Preload hero image -->
<link rel="preload" href="hero.webp" as="image" fetchpriority="high">
</head>
<body>
<div class="hero">
<div class="container">
<h1 class="display-4 fw-bold">Optimized Bootstrap</h1>
<p class="lead mb-4">Lighthouse score: Performance 98, Accessibility 100, Best Practices 95</p>
<a href="#" class="btn btn-light btn-lg px-4">Get Started</a>
</div>
</div>
<div class="container py-5">
<div class="row g-4">
<!-- Cards with lazy loaded images -->
<div class="col-md-4">
<div class="card p-4 h-100">
<img src="placeholder.svg" data-src="card1.webp" class="card-img-top lazy" alt="Card 1" width="400" height="250" loading="lazy">
<h5 class="card-title mt-2">Optimized Card</h5>
<p class="card-text text-body-secondary">Lazy-loaded WebP image, proper aspect ratio.</p>
</div>
</div>
<div class="col-md-4">
<div class="card p-4 h-100">
<img src="placeholder.svg" data-src="card2.webp" class="card-img-top lazy" alt="Card 2" width="400" height="250" loading="lazy">
<h5 class="card-title mt-2">Fast Loading</h5>
<p class="card-text text-body-secondary">Font display swap enabled.</p>
</div>
</div>
<div class="col-md-4">
<div class="card p-4 h-100">
<img src="placeholder.svg" data-src="card3.webp" class="card-img-top lazy" alt="Card 3" width="400" height="250" loading="lazy">
<h5 class="card-title mt-2">Accessible</h5>
<p class="card-text text-body-secondary">100 Accessibility score guaranteed.</p>
</div>
</div>
</div>
</div>
<!-- Deferred Bootstrap JS -->
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet">
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js" defer></script>
<!-- Lazy load images -->
<script>
document.addEventListener('DOMContentLoaded', function() {
const lazyImages = document.querySelectorAll('.lazy');
if ('IntersectionObserver' in window) {
const observer = new IntersectionObserver(function(entries) {
entries.forEach(function(entry) {
if (entry.isIntersecting) {
const img = entry.target;
img.src = img.dataset.src;
img.classList.remove('lazy');
observer.unobserve(img);
}
});
});
lazyImages.forEach(function(img) { observer.observe(img); });
}
});
</script>
</body>
</html>
输出: Bootstrap 5.3 样式生效的组件效果(如按钮、卡片、轮播、折叠等),页面默认采用 Bootstrap 默认主题(亮色)和响应式网格。
▶ 示例:CDN 多源回退加载
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>CDN with Fallback</title>
<!-- Primary CDN: jsDelivr -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css"
id="bootstrap-css"
integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH"
crossorigin="anonymous">
<!-- Fallback: if primary CDN fails, load from unpkg -->
<script>
window.onload = function() {
var css = document.getElementById('bootstrap-css');
if (css && !css.sheet) {
var fallback = document.createElement('link');
fallback.rel = 'stylesheet';
fallback.href = 'https://unpkg.com/bootstrap@5.3.3/dist/css/bootstrap.min.css';
document.head.appendChild(fallback);
}
};
</script>
</head>
<body>
<div class="container py-5">
<h1>CDN Multi-Source Fallback</h1>
<div class="alert alert-success">
<i class="bi bi-check-circle-fill me-2"></i> Bootstrap loaded successfully!
</div>
<p class="text-body-secondary">If jsDelivr is down, automatically falls back to unpkg.</p>
<div class="card p-4 shadow-sm">
<h5>CDN Source Chain</h5>
<ol class="mb-0">
<li class="mb-1"><strong>Primary:</strong> cdn.jsdelivr.net</li>
<li class="mb-1"><strong>Fallback 1:</strong> unpkg.com</li>
<li><strong>Fallback 2:</strong> cdnjs.cloudflare.com</li>
</ol>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"
integrity="sha384-YvpcrYf0tY3lHB60NNkmXc5s9fDVZLESaAA55NDzOxhy9GkcIdslK1eN7N6jIeHz"
crossorigin="anonymous"
defer></script>
<script>
// JS fallback — 在defer脚本之后运行
document.addEventListener('DOMContentLoaded', function() {
if (typeof bootstrap === 'undefined') {
var script = document.createElement('script');
script.src = 'https://unpkg.com/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js';
document.body.appendChild(script);
}
});
</script>
</body>
</html>
输出: Bootstrap 5.3 样式生效的组件效果(如按钮、卡片、轮播、折叠等),页面默认采用 Bootstrap 默认主题(亮色)和响应式网格。
▶ 示例:完整构建脚本
// package.json — Full build pipeline
{
"name": "bootstrap-production-build",
"version": "1.0.0",
"scripts": {
"clean": "rimraf dist",
"sass:compile": "sass scss/custom.scss:dist/css/style.css --style compressed",
"sass:watch": "sass scss/custom.scss:dist/css/style.css --watch",
"prefix": "postcss dist/css/style.css --use autoprefixer -o dist/css/style.prefixed.css",
"purge": "purgecss --config purgecss.config.js --output dist/css/style.min.css",
"js:bundle": "esbuild src/js/main.js --bundle --minify --outfile=dist/js/main.min.js",
"img:min": "imagemin src/images/* --out-dir=dist/images",
"copy:html": "cp src/*.html dist/",
"build:dev": "npm run clean && npm run sass:compile && npm run copy:html",
"build:prod": "npm run build:dev && npm run prefix && npm run purge && npm run js:bundle && npm run img:min",
"serve": "lite-server --baseDir='dist'",
"deploy": "npm run build:prod && gh-pages -d dist"
},
"devDependencies": {
"autoprefixer": "^10.4.17",
"esbuild": "^0.20.0",
"imagemin-cli": "^7.0.0",
"lite-server": "^2.6.1",
"postcss": "^8.4.33",
"postcss-cli": "^11.0.0",
"purgecss": "^6.0.0",
"rimraf": "^5.0.5",
"sass": "^1.70.0"
},
"dependencies": {
"bootstrap": "^5.3.3",
"bootstrap-icons": "^1.11.3"
}
}
# Full build commands
# Development
npm run build:dev # Compile SCSS + copy HTML
# Production
npm run build:prod # Compile → Autoprefix → Purge → Minify JS → Optimize images
# Local preview
npm run serve # Serve dist/ with auto-reload
# Deploy to GitHub Pages
npm run deploy # Build + publish
# Individual steps
npx sass scss/custom.scss dist/css/style.css --style compressed
npx postcss dist/css/style.css --use autoprefixer -o dist/css/style.prefixed.css
npx purgecss --css dist/css/style.prefixed.css --content dist/**/*.html --output dist/css/
npx esbuild src/js/main.js --bundle --minify --outfile=dist/js/main.min.js
(1) 优化优先级矩阵
graph TD
A[性能优化优先级] --> B[🛡️ P0: Critical]
A --> C[🔥 P1: High]
A --> D[⚡ P2: Medium]
A --> E[📋 P3: Low]
B --> B1[启用 Gzip/Brotli 压缩]
B --> B2[优化图片格式 WebP/AVIF]
B --> B3[移除未使用的 CSS]
B --> B4[启用 CDN 缓存]
C --> C1[延迟加载非关键 JS]
C --> C2[内联关键 CSS]
C --> C3[预连接到第三方域名]
D --> D1[字体 display:swap]
D --> D2[图片 lazy loading]
D --> D3[资源 Preload/Prefetch]
E --> E1[Service Worker 缓存]
E --> E2[HTTP/2 Server Push]
E --> E3[骨架屏加载]
输出: Bootstrap 5.3 样式生效的组件效果(如按钮、卡片、轮播、折叠等),页面默认采用 Bootstrap 默认主题(亮色)和响应式网格。
(2) 优化优先级矩阵表
| 优先级 | 优化项 | 预估收益 | 实施难度 | Lighthouse 指标 |
|---|---|---|---|---|
| P0 (Critical) | 启用 Gzip/Brotli | 减少 70-80% 体积 | 低(服务端配置) | FCP, LCP |
| P0 (Critical) | WebP/AVIF 图片格式 | 减少 30-50% 图片体积 | 中(构建脚本) | LCP |
| P0 (Critical) | PurgeCSS 移除无用样式 | 减少 60-80% CSS | 低(配置文件) | FCP |
| P1 (High) | 关键 CSS 内联 | 减少首屏渲染阻塞 | 中(需要工具) | FCP |
| P1 (High) | defer JS 加载 | 减少 JS 阻塞 | 低(加属性) | TBT |
| P1 (High) | CDN 预热 | 首次访问提速 | 中(需手动操作) | LCP |
| P2 (Medium) | 字体 display:swap | 消除 FOIT | 低(CSS 属性) | CLS |
| P2 (Medium) | 图片 lazy loading | 减少初始加载 | 低(加属性) | LCP |
| P3 (Low) | Service Worker 缓存 | 二次访问极速 | 高(需编写 SW) | 复用指标 |
(3) 部署平台对比表
| 平台 | 免费额度 | 自定义域名 | HTTPS | 部署方式 | CI/CD | 适合场景 |
|---|---|---|---|---|---|---|
| GitHub Pages | 无限(公开仓库) | ✅ | ✅ | git push |
GitHub Actions | 个人/开源项目 |
| Netlify | 100GB/月 | ✅ | ✅ | Git 连接 / CLI | 自动 | 静态站、Jamstack |
| Vercel | 100GB/月 | ✅ | ✅ | Git 连接 / CLI | 自动 | Next.js、前端项目 |
| Cloudflare Pages | 无限 | ✅ | ✅ | Git 连接 / CLI | 自动 | 全球 CDN 优先 |
| AWS S3 + CloudFront | 按量付费 | ✅ | ✅ | CLI / SDK | 可配 | 企业级生产 |
| 阿里云 OSS + CDN | 按量付费 | ✅ | ✅ | CLI / SDK | 可配 | 中国区用户 |
❓ 常见问题
btn-${color})需要加 safelist。建议在 PurgeCSS 配置的 safelist 中列出所有可能动态出现的 class 名称。📖 小节
- CSS 优化:按需编译 Sass + PurgeCSS 去冗余,CDN 使用
.min版本 - JS 优化:按需导入组件 +
defer延迟加载 - 图片优化:
loading="lazy"+ WebP/AVIF 格式 + 固定宽高 - 构建流程:
sass编译 >purgecss清理 > 部署上线 - Lighthouse 目标:FCP < 1.5s, LCP < 2.5s, CLS < 0.1
📝 作业
- ⭐ 对一个已有的 Bootstrap 项目运行 Lighthouse 审计,记录 FCP、LCP、CLS 三项指标,然后逐项优化直到各项达标。
- ⭐⭐ 配置 PurgeCSS:对一个使用 Bootstrap 的 HTML 文件运行 PurgeCSS,对比 purged 和 unpurged CSS 的体积差异。
- ⭐⭐⭐ 创建一个完整的
package.json脚本,包含 dev(watch)、build(sass + purge)、serve 三个命令。
上一课: 暗色模式