欢迎光临
我们一直在努力

04-性能优化与最佳实践——18. 资源压缩 - 图片与字体优化

18. 资源压缩 – 图片与字体优化

概述

资源压缩是前端性能优化的重要环节,通过压缩图片、字体等静态资源,可以显著减少资源大小,加快页面加载速度,提升用户体验。

维度内容
What 压缩图片、字体等静态资源
Why 减少资源大小,加快加载速度
When 有大量静态资源的项目
Where 构建配置、资源导入处
Who 需要优化资源加载的开发者
How 使用 imagemin、next/image、SVG 优化

1. 图片优化

1.1 图片格式选择

格式特点适用场景
JPEG 有损压缩,不支持透明 照片、复杂图像
PNG 无损压缩,支持透明 Logo、图标、简单图形
WebP 现代格式,体积更小 所有场景(浏览器支持)
AVIF 最新格式,压缩率最高 所有场景(现代浏览器)
SVG 矢量格式,无限缩放 图标、Logo、插图

// 使用 picture 元素提供多种格式
<picture>
<source srcSet="image.avif" type="image/avif" />
<source srcSet="image.webp" type="image/webp" />
<img src="image.jpg" alt="Description" />
</picture>

1.2 使用 Next.js Image 组件

import Image from 'next/image';

function OptimizedImage() {
return (
<Image
src="/large-image.jpg"
alt="Description"
width={800}
height={600}
priority={true} // 优先加载
loading="lazy" // 懒加载
sizes="(max-width: 768px) 100vw, 50vw"
quality={85} // 图片质量
/>
);
}

1.3 手动图片压缩工具

# 安装 imagemin CLI
npm install -g imagemin-cli

# 压缩图片
imagemin images/* –out-dir compressed-images

# 使用 sharp 库
npm install sharp

// sharp 压缩脚本
const sharp = require('sharp');
const fs = require('fs');
const path = require('path');

async function compressImage(inputPath, outputPath, options = {}) {
const {
width,
height,
quality = 80,
format = 'webp'
} = options;

let pipeline = sharp(inputPath);

if (width || height) {
pipeline = pipeline.resize(width, height, {
fit: 'cover',
position: 'center'
});
}

if (format === 'webp') {
pipeline = pipeline.webp({ quality });
} else if (format === 'avif') {
pipeline = pipeline.avif({ quality });
} else if (format === 'jpeg') {
pipeline = pipeline.jpeg({ quality });
}

await pipeline.toFile(outputPath);
console.log(`压缩完成: ${outputPath}`);
}

// 批量压缩
async function compressAll() {
const imagesDir = './src/images';
const outputDir = './src/images/compressed';

const files = fs.readdirSync(imagesDir);

for (const file of files) {
if (/\\.(jpg|jpeg|png)$/i.test(file)) {
const inputPath = path.join(imagesDir, file);
const outputPath = path.join(outputDir, file.replace(/\\.[^.]+$/, '.webp'));
await compressImage(inputPath, outputPath, { format: 'webp', quality: 80 });
}
}
}


2. Webpack 图片优化配置

2.1 使用 image-webpack-loader

npm install image-webpack-loader –save-dev

// webpack.config.js
module.exports = {
module: {
rules: [
{
test: /\\.(jpe?g|png|gif|svg)$/i,
use: [
{
loader: 'file-loader',
options: {
name: '[name].[hash].[ext]',
outputPath: 'images',
},
},
{
loader: 'image-webpack-loader',
options: {
mozjpeg: {
progressive: true,
quality: 65,
},
optipng: {
enabled: true,
},
pngquant: {
quality: [0.65, 0.90],
speed: 4,
},
gifsicle: {
interlaced: false,
},
webp: {
quality: 75,
},
},
},
],
},
],
},
};

2.2 使用 url-loader(小图片内联)

// webpack.config.js
module.exports = {
module: {
rules: [
{
test: /\\.(png|jpe?g|gif|svg)$/i,
use: [
{
loader: 'url-loader',
options: {
limit: 8192, // 8KB 以下的图片转为 Base64
name: '[name].[hash].[ext]',
outputPath: 'images',
fallback: 'file-loader',
},
},
],
},
],
},
};


3. Vite 图片优化

3.1 使用 vite-plugin-imagemin

npm install vite-plugin-imagemin –save-dev

// vite.config.js
import { defineConfig } from 'vite';
import viteImagemin from 'vite-plugin-imagemin';

export default defineConfig({
plugins: [
viteImagemin({
gifsicle: {
optimizationLevel: 7,
interlaced: false,
},
optipng: {
optimizationLevel: 7,
},
mozjpeg: {
quality: 80,
},
pngquant: {
quality: [0.8, 0.9],
speed: 4,
},
svgo: {
plugins: [
{
name: 'removeViewBox',
active: false,
},
{
name: 'removeEmptyAttrs',
active: true,
},
],
},
}),
],
});

3.2 自动生成 WebP

// vite.config.js
import { defineConfig } from 'vite';
import { ViteImageOptimizer } from 'vite-plugin-image-optimizer';

export default defineConfig({
plugins: [
ViteImageOptimizer({
test: /\\.(jpe?g|png|gif|tiff|webp|svg|avif)$/i,
exclude: undefined,
include: undefined,
includePublic: true,
logStats: true,
ansiColors: true,
svg: {
multipass: true,
plugins: [
{
name: 'preset-default',
params: {
overrides: {
cleanupNumericValues: false,
convertPathData: false,
mergePaths: false,
},
},
},
],
},
png: {
quality: 80,
},
jpeg: {
quality: 80,
},
jpg: {
quality: 80,
},
webp: {
lossless: false,
quality: 80,
},
avif: {
lossless: false,
quality: 80,
},
}),
],
});


4. SVG 优化

4.1 手动优化 SVG

# 使用 SVGO 优化 SVG
npm install -g svgo

# 优化单个文件
svgo input.svg -o output.svg

# 优化整个目录
svgo -f src/icons -o dist/icons

4.2 使用 SVGR 转换为 React 组件

npm install @svgr/webpack –save-dev

// webpack.config.js
module.exports = {
module: {
rules: [
{
test: /\\.svg$/,
use: ['@svgr/webpack', 'url-loader'],
},
],
},
};

// 使用 SVG 作为 React 组件
import { ReactComponent as Icon } from './icon.svg';

function App() {
return <Icon className="icon" />;
}

4.3 使用 Vite 处理 SVG

// vite.config.js
import { defineConfig } from 'vite';
import svgr from 'vite-plugin-svgr';

export default defineConfig({
plugins: [svgr()],
});

// 使用
import Icon from './icon.svg?react';

function App() {
return <Icon className="icon" />;
}


5. 字体优化

5.1 字体格式选择

格式特点支持度
WOFF2 压缩率最高 现代浏览器
WOFF 压缩率中等 广泛支持
TTF 未压缩 所有浏览器
EOT IE 专用 仅 IE

5.2 字体子集化

# 使用 fonttools 创建字体子集
pip install fonttools

# 提取需要的字符
pyftsubset font.ttf \\
–text="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" \\
–output-file=font-subset.ttf

5.3 使用 Google Fonts 优化

<!– 预连接 –>
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />

<!– 使用 display=swap 避免 FOIT –>
<link href="https://fonts.googleapis.com/css2?family=Roboto:wght@400;700&display=swap" rel="stylesheet" />

5.4 自托管字体配置

/* fonts.css */
@font-face {
font-family: 'CustomFont';
src: url('/fonts/custom-font.woff2') format('woff2'),
url('/fonts/custom-font.woff') format('woff');
font-weight: 400;
font-style: normal;
font-display: swap; /* 避免 FOIT */
}

@font-face {
font-family: 'CustomFont';
src: url('/fonts/custom-font-bold.woff2') format('woff2'),
url('/fonts/custom-font-bold.woff') format('woff');
font-weight: 700;
font-style: normal;
font-display: swap;
}


6. 懒加载图片

6.1 原生懒加载

// 使用 loading="lazy"
<img src="large-image.jpg" alt="Description" loading="lazy" />

// 使用 Intersection Observer
import { useEffect, useRef, useState } from 'react';

function LazyImage({ src, alt, placeholder }) {
const [imageSrc, setImageSrc] = useState(placeholder);
const imgRef = useRef(null);

useEffect(() => {
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
setImageSrc(src);
observer.disconnect();
}
});
});

if (imgRef.current) {
observer.observe(imgRef.current);
}

return () => observer.disconnect();
}, [src]);

return <img ref={imgRef} src={imageSrc} alt={alt} />;
}

6.2 React Lazy Load Image 组件

npm install react-lazy-load-image-component

import { LazyLoadImage } from 'react-lazy-load-image-component';
import 'react-lazy-load-image-component/src/effects/blur.css';

function ImageGallery() {
return (
<div>
<LazyLoadImage
src="large-image.jpg"
alt="Description"
effect="blur"
placeholderSrc="placeholder.jpg"
threshold={100}
width={800}
height={600}
/>
</div>
);
}


7. 完整示例:图片优化流程

// scripts/optimize-images.js
const sharp = require('sharp');
const fs = require('fs-extra');
const path = require('path');

const inputDir = './src/images/original';
const outputDir = './src/images/optimized';

async function optimizeImages() {
await fs.ensureDir(outputDir);

const files = await fs.readdir(inputDir);

for (const file of files) {
const inputPath = path.join(inputDir, file);
const ext = path.extname(file).toLowerCase();
const name = path.basename(file, ext);

if (['.jpg', '.jpeg', '.png'].includes(ext)) {
// 生成 WebP 版本
await sharp(inputPath)
.webp({ quality: 80 })
.toFile(path.join(outputDir, `${name}.webp`));

// 生成 AVIF 版本
await sharp(inputPath)
.avif({ quality: 70 })
.toFile(path.join(outputDir, `${name}.avif`));

// 生成不同尺寸
const sizes = [400, 800, 1200];
for (const size of sizes) {
await sharp(inputPath)
.resize(size, null, { withoutEnlargement: true })
.jpeg({ quality: 80 })
.toFile(path.join(outputDir, `${name}${size}.jpg`));
}
}
}

console.log('图片优化完成!');
}

optimizeImages();


8. 总结

核心要点

要点说明
图片格式 使用 WebP/AVIF 替代传统格式
压缩工具 imagemin、sharp、image-webpack-loader
懒加载 loading=“lazy” + Intersection Observer
字体优化 WOFF2 格式 + 子集化 + font-display: swap

资源优化检查清单

  • 图片使用现代格式(WebP/AVIF)
  • 图片已压缩
  • 实现图片懒加载
  • 使用响应式图片(srcset)
  • SVG 已优化
  • 字体使用 WOFF2 格式
  • 配置 font-display: swap
  • 小图片内联为 Base64

记忆口诀

图片压缩格式新,WebP AVIF 来替代 懒加载交互相应快,字体子集体积小 响应式图 srcset,不同设备都适用


9. 相关资源

  • Sharp 文档
  • WebP 介绍
  • AVIF 介绍
  • Google Fonts 优化

赞(0)
未经允许不得转载:171主机测评 » 04-性能优化与最佳实践——18. 资源压缩 - 图片与字体优化
分享到: 更多 (0)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址