图片优化与 NuxtImg

图片通常占据网页总传输量的 50% 以上。对于视频平台,每个视频都有封面图、缩略图、用户头像——未优化的图片会严重拖慢 LCP 和整体加载速度。Nuxt4 通过 @nuxt/image 模块提供了自动格式转换、响应式尺寸、懒加载、CDN 集成等能力,让图片优化从手动苦力变成声明式配置。

1. 为什么图片优化如此重要

1.1 图片对性能的影响

一张未优化的 PNG 封面图可能有 2-5MB,而经过格式转换 + 尺寸适配后只需 50-200KB——体积减少 90% 以上。具体影响:

指标影响
LCP首屏最大内容绘制,如果最大元素是图片,加载越慢 LCP 越差
带宽移动端用户流量有限,大图浪费带宽
CLS图片没有预设尺寸时,加载后导致布局偏移
服务器成本CDN 流量费按传输量计费,图片越大成本越高

1.2 优化的四个维度

  1. 格式:AVIF > WebP > JPEG > PNG(同质量下体积递减)
  2. 尺寸:按屏幕宽度提供不同分辨率,移动端不需要 4K 图
  3. 加载时机:首屏图片立即加载,非首屏图片懒加载
  4. 缓存:CDN 缓存 + 浏览器缓存,避免重复下载

2. @nuxt/image 模块

2.1 安装与配置

// nuxt.config.ts
export default defineNuxtConfig({
  modules: ['@nuxt/image'],
  image: {
    quality: 80,           // 默认压缩质量
    format: ['avif', 'webp'],  // 优先使用的格式(自动回退)
    screens: {              // 响应式断点
      xs: 320,
      sm: 640,
      md: 768,
      lg: 1024,
      xl: 1280,
      xxl: 1536,
    },
  },
})

2.2 NuxtImg 组件

<NuxtImg><img> 的增强替代,自动处理格式转换和尺寸优化:

<template>
  <!-- 基础用法:自动转 WebP/AVIF,自动设置 srcset -->
  <NuxtImg
    src="/images/hero.jpg"
    width="1200"
    height="630"
    alt="AI 视频平台首页"
  />
 
  <!-- 响应式尺寸:不同屏幕加载不同分辨率 -->
  <NuxtImg
    src="/images/hero.jpg"
    sizes="sm:100vw md:50vw lg:400px"
    alt="响应式图片"
  />
 
  <!-- 懒加载:非首屏图片 -->
  <NuxtImg
    src="/images/thumbnail.jpg"
    loading="lazy"
    placeholder
    alt="视频缩略图"
  />
</template>

2.3 NuxtPicture 组件

&lt;NuxtPicture&gt; 生成 &lt;picture&gt; 标签,支持多格式源和 art direction:

<template>
  <NuxtPicture
    src="/images/banner.jpg"
    format="avif,webp"
    sizes="sm:100vw lg:1200px"
    alt="横幅"
  />
  <!-- 生成的 HTML:
  <picture>
    <source type="image/avif" srcset="..." sizes="...">
    <source type="image/webp" srcset="..." sizes="...">
    <img src="..." alt="横幅">
  </picture>
  -->
</template>

浏览器会按 &lt;source&gt; 顺序选择它支持的第一个格式——支持 AVIF 的用 AVIF,不支持的回退到 WebP,再不支持的用原始 JPEG。

3. 格式转换深度解析

3.1 现代图片格式对比

格式体积(相对 JPEG)浏览器支持特点
AVIF50-70%Chrome 85+, Firefox 93+最小体积,编码较慢
WebP70-80%所有现代浏览器兼容性好,体积适中
JPEG100%(基准)全部照片类图片的传统选择
PNG200-500%全部透明图片、UI 元素
SVG极小全部矢量图标、Logo

3.2 格式选择策略

  • 照片/封面图:AVIF 优先,WebP 回退(format: ['avif', 'webp']
  • 透明图片:WebP(支持 alpha 通道),PNG 回退
  • 图标/Logo:SVG(矢量,无限缩放,体积极小)
  • 动图:WebP 动图替代 GIF(体积减少 60%+)

3.3 质量与体积的平衡

quality 参数控制压缩程度。经验值:

场景quality原因
视频封面图75-80用户会仔细看,质量不能太低
列表缩略图60-70尺寸小,质量损失不明显
背景图50-60通常有遮罩/模糊,质量要求低
用户头像80尺寸极小(≤200px),高质量也不大

4. 响应式图片

4.1 sizes 属性详解

sizes 告诉浏览器图片在不同视口宽度下的实际显示尺寸,浏览器据此选择最合适的 srcset 图片:

<!-- 移动端全宽,平板半宽,桌面固定 400px -->
<NuxtImg src="/cover.jpg" sizes="sm:100vw md:50vw lg:400px" />

生成的 HTML:

<img
  src="/cover.jpg"
  srcset="
    /cover-320w.webp 320w,
    /cover-640w.webp 640w,
    /cover-1024w.webp 1024w,
    /cover-1280w.webp 1280w
  "
  sizes="(max-width: 640px) 100vw, (max-width: 1024px) 50vw, 400px"
/>

4.2 densities 属性

为高 DPI 屏幕(Retina)提供 2x/3x 分辨率图片:

<NuxtImg src="/avatar.jpg" width="100" densities="x1 x2" />
<!-- 生成 srcset: avatar-100w.webp 1x, avatar-200w.webp 2x -->

4.3 最佳实践

  • 始终设置 widthheight:浏览器据此计算宽高比,预留空间避免 CLS
  • 使用 sizes 而非固定宽度:让浏览器根据视口选择最优图片
  • 移动端优先sizes="100vw md:50vw lg:400px",默认全宽,大屏收窄

5. 加载策略

5.1 首屏图片:preload + fetchpriority

首屏最大的图片(通常是 Hero Banner 或视频封面)直接影响 LCP,应优先加载:

<!-- 首屏 Hero 图片:禁用懒加载,高优先级 -->
<NuxtImg
  src="/hero.jpg"
  loading="eager"
  fetchpriority="high"
  preload
  sizes="100vw"
/>

preload 属性会在 &lt;head&gt; 中注入 &lt;link rel="preload"&gt;,让浏览器在解析 HTML 时就开始下载图片,而不是等到渲染到 &lt;img&gt; 标签时才开始。

5.2 非首屏图片:lazy + placeholder

<!-- 列表中的缩略图:懒加载 + 低质量占位图 -->
<NuxtImg
  src="/thumbnails/video-123.jpg"
  loading="lazy"
  placeholder="/thumbnails/video-123-blur.jpg"
  width="320"
  height="180"
/>

placeholder 可以是:

  • 低质量缩略图(LQIP):10-20px 宽的模糊小图,只有几百字节
  • CSS 占位色:placeholder="#f3f4f6"
  • 自动生成:placeholder(不带值,@nuxt/image 自动生成 LQIP)

5.3 Intersection Observer 原生懒加载

loading="lazy" 是浏览器原生懒加载,无需 JavaScript,性能最优。但它的触发距离不可控——浏览器通常在距视口 1250px 时就开始加载。如果需要更精细的控制,可以用 Intersection Observer:

// app/composables/useLazyImage.ts
export function useLazyImage(threshold = 0.1) {
  const imageRef = ref<HTMLImageElement | null>(null)
  const isVisible = ref(false)
 
  onMounted(() => {
    if (!imageRef.value) return
    const observer = new IntersectionObserver(([entry]) => {
      if (entry.isIntersecting) {
        isVisible.value = true
        observer.disconnect()
      }
    }, { threshold })
    observer.observe(imageRef.value)
  })
 
  return { imageRef, isVisible }
}

6. 图片 CDN 集成

6.1 Provider 机制

@nuxt/image 内置了 20+ 个图片 CDN Provider,通过配置即可切换:

// nuxt.config.ts
export default defineNuxtConfig({
  image: {
    provider: 'cloudflare',  // 或 'imgix', 'cloudinary', 'vercel' 等
    cloudflare: {
      baseURL: 'https://images.example.com',
    },
  },
})

图片 CDN 的优势:

  • 边缘转换:在 CDN 边缘节点实时转换格式和尺寸,无需预生成
  • 全球缓存:图片缓存在离用户最近的节点
  • 自动格式:根据请求的 Accept 头自动选择最优格式

6.2 自定义 Provider

如果用阿里云 OSS、腾讯云 COS 等国内 CDN,可以自定义 Provider:

// providers/aliyun-oss.ts
export function getImage(src: string, { modifiers, baseURL }: any) {
  const operations = []
  if (modifiers.width) operations.push(`w_${modifiers.width}`)
  if (modifiers.height) operations.push(`h_${modifiers.height}`)
  if (modifiers.quality) operations.push(`q_${modifiers.quality}`)
  if (modifiers.format) operations.push(`fmt_${modifiers.format}`)
 
  const suffix = operations.length ? `?x-oss-process=image/resize,${operations.join(',')}` : ''
  return { url: `${baseURL}${src}${suffix}` }
}

6.3 CDN vs 本地处理

维度图片 CDN本地处理(IPX)
部署要求需要 CDN 服务无额外依赖
转换时机请求时实时转换构建时或首次请求时
缓存CDN 全球缓存服务器本地缓存
成本按转换次数/流量计费仅服务器 CPU
适用场景生产环境开发/小型项目

7. AI 视频封面图优化方案

7.1 封面图生成链路

AI 视频生成后通常会截取关键帧作为封面图。优化链路:

AI 生成视频 → 截取关键帧(原图 1920×1080 PNG ~3MB)
  → 上传到 OSS/S3
  → 通过图片 CDN 按需转换:
     - 列表缩略图:320×180 WebP ~15KB
     - 详情页封面:1280×720 AVIF ~80KB
     - OG 分享图:1200×630 JPEG ~120KB(社交平台兼容性)

7.2 视频列表组件

<!-- components/VideoCard.vue -->
<template>
  <div class="video-card">
    <NuxtImg
      :src="`/videos/${video.id}/cover.jpg`"
      :alt="video.title"
      width="320"
      height="180"
      loading="lazy"
      placeholder
      sizes="sm:100vw md:320px"
      format="avif,webp"
      quality="70"
    />
    <h3>{{ video.title }}</h3>
  </div>
</template>

7.3 性能收益量化

优化项优化前优化后收益
封面图格式PNG 3MBAVIF 80KB-97%
缩略图格式JPEG 200KBWebP 15KB-92%
列表页总图片量(20 张)4MB300KB-92%
LCP(3G 网络)4.2s1.8s-57%

本章小结

  • 格式优先级:AVIF > WebP > JPEG,@nuxt/image 自动协商最优格式
  • 响应式图片sizes 属性让浏览器按视口选择最优尺寸,避免移动端下载大图
  • 加载策略:首屏 preload + fetchpriority="high",非首屏 loading="lazy" + placeholder
  • 尺寸预占:始终设置 width / height,防止 CLS 布局偏移
  • CDN 集成:生产环境用图片 CDN(Cloudflare/阿里云 OSS),边缘实时转换
  • 量化收益:格式转换 + 尺寸适配可减少 90%+ 图片传输量,LCP 提升显著