图片优化
图片通常占网页体积的 50% 以上,优化图片是提升性能最有效的手段之一。Nuxt 通过 @nuxt/image 模块提供开箱即用的图片优化功能。
为什么需要图片优化?
| 问题 | 未优化 | 优化后 |
|---|---|---|
| 文件体积 | 原始 2MB 的 JPEG | 转为 WebP 后 500KB(减少 75%) |
| 布局偏移(CLS) | 图片加载后页面跳动 | 指定宽高,零偏移 |
| 加载体验 | 白屏等待 | 懒加载 + 占位符 + 渐进式 |
| 响应式 | 同一大图适配所有设备 | 按设备尺寸加载合适图片 |
| 缓存 | URL 不变,缓存无法更新 | 内容哈希,自动更新 |
图片优化对 Core Web Vitals 的影响
- LCP(最大内容绘制):图片压缩 → 更快的 LCP
- CLS(布局偏移):指定宽高 → 零 CLS
- FCP(首次内容绘制):懒加载非首屏图片 → 更快的 FCP
安装
bash
npm install @nuxt/imagets
export default defineNuxtConfig({
modules: ['@nuxt/image'],
})@nuxt/image 做了什么?
- 提供
<NuxtImg>和<NuxtPicture>组件 - 自动转换图片格式(WebP、AVIF)
- 按请求的尺寸裁剪和压缩
- 生成
srcset实现响应式图片 - 内置懒加载和占位符功能
NuxtImg
<NuxtImg> 是 <img> 的直接替代品,自动优化图片:
基本用法
vue
<template>
<!-- 基本用法:和 <img> 一样 -->
<NuxtImg src="/images/photo.jpg" alt="Photo" />
<!-- 指定宽高(推荐!避免 CLS) -->
<NuxtImg src="/images/photo.jpg" width="400" height="300" alt="Photo" />
<!-- 指定格式:转为 WebP -->
<NuxtImg src="/images/photo.jpg" format="webp" width="400" height="300" />
<!-- 指定质量 -->
<NuxtImg src="/images/photo.jpg" quality="80" width="400" height="300" />
<!-- 懒加载(非首屏图片) -->
<NuxtImg src="/images/photo.jpg" loading="lazy" width="400" height="300" />
<!-- 占位符:加载时显示模糊缩略图 -->
<NuxtImg src="/images/photo.jpg" placeholder width="400" height="300" />
</template><NuxtImg> vs <img>
<NuxtImg>在构建时或运行时通过图片 Provider 处理图片- 如果只指定了
src,不做任何优化(和<img>一样) - 指定
width、height、format等属性后才会触发优化
响应式图片
vue
<template>
<!-- 不同屏幕尺寸加载不同大小的图片 -->
<NuxtImg
src="/images/photo.jpg"
width="400"
height="300"
densities="x1 x2"
sizes="sm:100vw md:50vw lg:400px"
alt="Photo"
/>
</template>sizes 的含义
sm:100vw→ 小屏幕:图片占 100% 视口宽度md:50vw→ 中等屏幕:图片占 50% 视口宽度lg:400px→ 大屏幕:图片固定 400px
浏览器根据 sizes 和设备像素密度,选择最合适的图片尺寸下载。
NuxtImg Props 完整列表
| Prop | 类型 | 说明 | 示例 |
|---|---|---|---|
src | string | 图片路径 | /images/photo.jpg |
width | number | 宽度(px) | 400 |
height | number | 高度(px) | 300 |
format | string | 格式:webp、avif、jpg、png | webp |
quality | number | 质量:0-100 | 80 |
fit | string | 裁剪方式:cover、contain、fill | cover |
modifiers | object | 自定义修饰符 | { grayscale: true } |
placeholder | boolean | 显示加载占位符 | true |
loading | string | 加载方式:lazy 或 eager | lazy |
densities | string | 设备像素密度 | x1 x2 |
sizes | string | 响应式尺寸规则 | sm:100vw lg:400px |
preload | boolean | 预加载(首屏关键图片) | true |
decoding | string | 解码方式:auto、async、sync | async |
NuxtPicture
<NuxtPicture> 是 <picture> 的替代品,自动生成多种格式的图片,浏览器选择最优格式:
vue
<template>
<!-- 自动生成 WebP + 原始格式 -->
<NuxtPicture
src="/images/photo.jpg"
width="400"
height="300"
alt="Photo"
/>
<!-- 渲染结果:
<picture>
<source type="image/webp" srcset="...webp" />
<source type="image/jpeg" srcset="...jpg" />
<img src="...jpg" width="400" height="300" alt="Photo" />
</picture>
-->
<!-- 指定格式 -->
<NuxtPicture
src="/images/photo.jpg"
format="avif"
width="400"
height="300"
alt="Photo"
/>
</template>NuxtPicture vs NuxtImg
| 特性 | NuxtImg | NuxtPicture |
|---|---|---|
| 输出元素 | <img> | <picture> + <source> |
| 多格式 | ❌ 单一格式 | ✅ 自动生成多种格式 |
| 浏览器兼容 | 所有浏览器 | 不支持 WebP/AVIF 的浏览器自动降级 |
| 适用场景 | 简单场景、固定格式 | 需要多格式优化、最大兼容性 |
推荐
首屏关键图片用 <NuxtPicture>(自动选择最优格式),非关键图片用 <NuxtImg format="webp">(代码更简洁)。
图片 Provider
@nuxt/image 通过 Provider 实现图片转换。不同 Provider 适用于不同场景:
本地图片(ipx,默认)
vue
<NuxtImg src="/images/photo.jpg" width="400" />
<!-- 对应 public/images/photo.jpg -->ipx
是默认的本地图片处理 Provider,使用 sharp 在服务端进行图片转换。开发模式和生产模式都可用。
远程图片
ts
// nuxt.config.ts
export default defineNuxtConfig({
image: {
// 允许的远程域名
domains: ['images.unsplash.com', 'cdn.example.com'],
},
})vue
<NuxtImg src="https://images.unsplash.com/photo-xxx" width="400" />INFO
️ 远程图片必须配置 domains 否则 @nuxt/image 不会处理
常用 Provider
| Provider | 说明 | 适用场景 |
|---|---|---|
ipx | 默认,本地图片处理 | 自托管、简单项目 |
cloudinary | Cloudinary CDN | 使用 Cloudinary 的项目 |
fastly | Fastly CDN | 使用 Fastly 的项目 |
imgix | Imgix CDN | 使用 Imgix 的项目 |
prismic | Prismic CMS | 使用 Prismic 的项目 |
storyblok | Storyblok CMS | 使用 Storyblok 的项目 |
strapi | Strapi CMS | 使用 Strapi 的项目 |
twicpics | TwicPics | 使用 TwicPics 的项目 |
vercel | Vercel OG | 部署在 Vercel 的项目 |
ts
export default defineNuxtConfig({
image: {
provider: 'cloudinary',
cloudinary: {
baseURL: 'https://res.cloudinary.com/my-cloud/image/upload/',
},
},
})Provider 选择建议
- 自托管 / 开发:用
ipx(默认,无需配置) - 生产环境 + CDN:用 Cloudinary / imgix 等(全球 CDN 加速)
- 部署在 Vercel:用
vercel(自动集成)
预设尺寸
定义常用的图片尺寸预设,避免在每个组件中重复写属性:
ts
export default defineNuxtConfig({
image: {
presets: {
avatar: {
modifiers: {
format: 'webp',
width: 100,
height: 100,
fit: 'cover',
},
},
hero: {
modifiers: {
format: 'webp',
width: 1200,
quality: 80,
},
},
thumbnail: {
modifiers: {
format: 'webp',
width: 200,
height: 150,
fit: 'cover',
quality: 70,
},
},
},
},
})vue
<template>
<!-- 使用预设 -->
<NuxtImg src="/images/user.jpg" preset="avatar" />
<NuxtImg src="/images/banner.jpg" preset="hero" />
<NuxtImg src="/images/product.jpg" preset="thumbnail" />
<!-- 预设 + 覆盖 -->
<NuxtImg src="/images/user.jpg" preset="avatar" quality="90" />
</template>图片格式选择
| 格式 | 压缩率 | 透明度 | 浏览器支持 | 适用场景 |
|---|---|---|---|---|
| WebP | 比 JPEG 小 25-35% | ✅ | 97%+ | 推荐首选 |
| AVIF | 比 WebP 再小 20% | ✅ | 92%+ | 追求极致压缩 |
| JPEG | 基准 | ❌ | 100% | 不支持 WebP 的降级 |
| PNG | 无损 | ✅ | 100% | 需要精确像素的图 |
| SVG | 矢量 | ✅ | 100% | 图标、Logo、插图 |
格式选择建议
- 照片类图片:
WebP(推荐)或AVIF(前沿) - 需要透明度的图片:
WebP(有透明通道)或PNG - 图标和 Logo:
SVG(矢量,任意缩放不失真) - 使用
<NuxtPicture>:自动生成 WebP + 降级格式
图片最佳实践
1. 总是指定宽高——避免 CLS
vue
<!-- ❌ 不指定宽高:图片加载后页面跳动(CLS 问题) -->
<NuxtImg src="/images/photo.jpg" alt="Photo" />
<!-- ✅ 指定宽高:页面加载时预留空间,零 CLS -->
<NuxtImg src="/images/photo.jpg" width="400" height="300" alt="Photo" />CLS(Cumulative Layout Shift)
布局偏移是 Core Web Vitals 的重要指标。图片没有宽高时,浏览器在图片加载前不知道它的大小,加载后会"推"开其他内容。
2. 首屏图片预加载
vue
<template>
<!-- 首屏关键图片:预加载 + 高优先级 -->
<NuxtImg
src="/images/hero.jpg"
width="1200"
height="600"
preload
loading="eager"
fetchpriority="high"
format="webp"
alt="Hero"
/>
<!-- 非首屏图片:懒加载 -->
<NuxtImg
src="/images/content.jpg"
width="400"
height="300"
loading="lazy"
format="webp"
alt="Content"
/>
</template>3. 使用占位符提升体验
vue
<template>
<!-- 加载时显示模糊缩略图,加载完成后切换为清晰图片 -->
<NuxtImg
src="/images/photo.jpg"
width="400"
height="300"
placeholder
format="webp"
alt="Photo"
/>
</template>占位符的原理
@nuxt/image 会生成一个极小(10-20px)的模糊缩略图,作为 src 显示。当完整图片加载完成后,替换为清晰图片。用户体验是从模糊到清晰的平滑过渡。
4. 响应式图片
vue
<template>
<!-- 不同屏幕加载不同尺寸 -->
<NuxtImg
src="/images/photo.jpg"
width="800"
height="600"
sizes="sm:100vw md:50vw lg:800px"
densities="x1 x2"
format="webp"
alt="Photo"
/>
</template>知识脉络
text
CSS 与 SCSS → 资源管理 → 你在这里:图片优化
│
├─→ 下一步:字体
│
└─→ 相关:内置组件速查 → NuxtImg / NuxtPicture