Picovert

把 GIF 换成 MP4,Lighthouse 分数从 64 提到 92 的实录

Picovert 团队2026-04-258 分钟阅读

我们有一张营销落地页,首屏放着三段动画 GIF —— 一段展示产品工作的主视觉循环,加两段功能 动画。合计 11 MB。Lighthouse 给手机端打了 64 分,LCP 4.2 秒,Total Blocking Time 380 ms。把这三段 GIF 换成 MP4 —— 视觉内容相同、循环行为相同 —— 一个下午就把分数推到 了 92。本文是这次操作的全程记录。

起点

页面是一个相当标准的 Next.js 营销站。Tailwind、静态生成、部署到 Vercel。三段 GIF 都是从 After Effects 用 720p、30fps、中等优化导出的。大小:

  • 主视觉动画(5 秒,720p):5.8 MB
  • 功能 1(3 秒,600p):2.9 MB
  • 功能 2(4 秒,600p):2.4 MB

动画总传输量:11.1 MB。在 Slow 4G(Lighthouse 移动端档位)下,差不多要 27 秒才能完整加载。 页面文本很快渲染出来,但主视觉一直停在"加载中"的占位上太久 —— 这正是 LCP 要扣分的状态。

起点的 Lighthouse 报告

指标分数
Performance64
Largest Contentful Paint4.2 秒
Total Blocking Time380 ms
Speed Index5.8 秒
Cumulative Layout Shift0.04

转换

我们用两套设置把每段 GIF 都跑了 ffmpeg:H.264 的 MP4 用作广覆盖兜底,VP9 的 WebM 给支持 的浏览器更小的传输量。命令:

ffmpeg -i hero.gif -movflags faststart -pix_fmt yuv420p -crf 22 -vf "scale=trunc(iw/2)*2:trunc(ih/2)*2:flags=lanczos" -an hero.mp4

ffmpeg -i hero.gif -c:v libvpx-vp9 -crf 30 -b:v 0 -deadline good -cpu-used 2 -row-mt 1 -pix_fmt yuv420p -an hero.webm

转换后的体积令人印象深刻:

资源GIFMP4 (H.264)WebM (VP9)
主视觉5.8 MB320 KB (-94%)240 KB (-96%)
功能 12.9 MB180 KB (-94%)140 KB (-95%)
功能 22.4 MB150 KB (-94%)110 KB (-95%)

总传输量从 11.1 MB 降到 650 KB(H.264),VP9 下是 490 KB。17–22 倍的削减。

标记的改动

原标记是 <img src="hero.gif" alt="...">。替换后:

<video autoplay loop muted playsinline poster="hero-poster.jpg">
<source src="hero.webm" type="video/webm">
<source src="hero.mp4" type="video/mp4">
</video>

poster 是视频开始解码前显示的一张静帧(JPEG,约 30 KB)。这是解锁 LCP 的关键 —— 浏览器会把这张 poster 当作"有内容的绘制",于是 1 秒内就达到了。

转换后的 Lighthouse 报告

指标
Performance6492
LCP4.2 秒1.4 秒
TBT380 ms110 ms
Speed Index5.8 秒1.9 秒
CLS0.040.02

LCP 降了 67%,TBT 降了 71%。TBT 改善的原因:软件 GIF 解码原本在每一帧都阻塞主线程;硬件 MP4 解码会卸载到单独的进程。

注意事项与坑

  • autoplay 需要 muted。iOS 和 2018 年以后的多数浏览器都会拦下含音视频的 自动播放。autoplay 的循环视频上始终设 muted
  • iOS 需要 playsinline。否则 iOS 在轻触时会把视频拉成全屏播放器。
  • H.264 要求偶数尺寸。该编码器要求宽高都被 2 整除。用 scale=trunc(iw/2)*2:trunc(ih/2)*2 滤镜。
  • Safari 需要 yuv420p。其他像素格式 Chrome 能解,Safari 会静默失败。
  • 不要把视频用于静态装饰。如果"动画"几乎不动(缓慢的 zoom、轻微的 pan), 静态图或 CSS 动画都更便宜。

Lighthouse 之外:真实用户层面的影响

Lighthouse 的数字是合成分。真正要看的是现场数据 —— 真实网络中的真实访客。改动后两周内 我们看到:

  • 线上 p75 LCP:3.8 秒 → 1.6 秒(Chrome User Experience Report)
  • 跳出率:移动端 -8%(GA 数据)
  • CDN 流量账单:仅营销站每月 -$340

带宽节省其实比不上之前用调色板技巧和抖动死磕 GIF 浪费掉的工程时间。一旦跨过格式边界, 那些挣扎都不重要了。

怎么在自己站点上做这件事

把分数从 64 推到 92 的五步:

  1. 在 DevTools 的 Network 面板里找出页面上每一个 .gif
  2. 把每一个都转成 MP4 (H.264) 和 WebM (VP9)。一次性可以用我们的 GIF → MP4 转换工具,两种格式都能出,全程跑在浏览器 内。要进流水线就用上面的 ffmpeg 命令。
  3. 为每段视频生成一张静帧 JPEG poster。ffmpeg -i input.gif -vf "select=eq(n\\,0)" -vframes 1 poster.jpg
  4. 按上面的写法把每个 <img> 换成 <video>
  5. 重新跑 Lighthouse。确认分数跳了,LCP 降了。

总耗时:我们维护的站点里,每页大约 20 分钟。在数千用户的每次页面访问上复利累积下来,这是 我们这一年里做过的单笔回报最高的性能修复。