Skip to content

图片优化

图片通常占网页体积的 50% 以上,优化图片是提升性能最有效的手段之一。Nuxt 通过 @nuxt/image 模块提供开箱即用的图片优化功能。

为什么需要图片优化?

问题未优化优化后
文件体积原始 2MB 的 JPEG转为 WebP 后 500KB(减少 75%)
布局偏移(CLS)图片加载后页面跳动指定宽高,零偏移
加载体验白屏等待懒加载 + 占位符 + 渐进式
响应式同一大图适配所有设备按设备尺寸加载合适图片
缓存URL 不变,缓存无法更新内容哈希,自动更新

图片优化对 Core Web Vitals 的影响

  • LCP(最大内容绘制):图片压缩 → 更快的 LCP
  • CLS(布局偏移):指定宽高 → 零 CLS
  • FCP(首次内容绘制):懒加载非首屏图片 → 更快的 FCP

安装

bash
npm install @nuxt/image
ts
export default defineNuxtConfig({
  modules: ['@nuxt/image'],
})

@nuxt/image 做了什么?

  1. 提供 <NuxtImg><NuxtPicture> 组件
  2. 自动转换图片格式(WebP、AVIF)
  3. 按请求的尺寸裁剪和压缩
  4. 生成 srcset 实现响应式图片
  5. 内置懒加载和占位符功能

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> 一样)
  • 指定 widthheightformat 等属性后才会触发优化

响应式图片

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类型说明示例
srcstring图片路径/images/photo.jpg
widthnumber宽度(px)400
heightnumber高度(px)300
formatstring格式:webpavifjpgpngwebp
qualitynumber质量:0-10080
fitstring裁剪方式:covercontainfillcover
modifiersobject自定义修饰符{ grayscale: true }
placeholderboolean显示加载占位符true
loadingstring加载方式:lazyeagerlazy
densitiesstring设备像素密度x1 x2
sizesstring响应式尺寸规则sm:100vw lg:400px
preloadboolean预加载(首屏关键图片)true
decodingstring解码方式:autoasyncsyncasync

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

特性NuxtImgNuxtPicture
输出元素<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默认,本地图片处理自托管、简单项目
cloudinaryCloudinary CDN使用 Cloudinary 的项目
fastlyFastly CDN使用 Fastly 的项目
imgixImgix CDN使用 Imgix 的项目
prismicPrismic CMS使用 Prismic 的项目
storyblokStoryblok CMS使用 Storyblok 的项目
strapiStrapi CMS使用 Strapi 的项目
twicpicsTwicPics使用 TwicPics 的项目
vercelVercel 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
  • 图标和 LogoSVG(矢量,任意缩放不失真)
  • 使用 <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

基于 Nuxt 4 官方文档整理编写