[特殊字符] Web 图片优化实践:通过 AVIF/WebP 将 12MB 图片降至 4MB
是由 Google 推出的一种现代图片格式,提供有损和无损压缩两种模式。相比 PNG,WebP 无损压缩可减少 26% 的文件大小;相比 JPG,WebP 有损压缩可减少 25-34% 的文件大小。Next.js + AI-SDK + DeepSeek:3 分钟建设属于你的 AI 问答 DemoWebP 还支持动画和透明通道,是 GIF 和 PNG 的理想替代方案。目前,WebP 已得到所有现代浏
常规解决方案
一般情况下,前端开发主要使用<img>
标签及 PNG/JPG 格式,再一定程度结合图片压缩、懒加载、CDN(多节点分发、缓存预热)等优化方案来满足性能要求。部分 CDN 平台还提供一站式图片解决方案,例如图片压缩、裁剪、格式转换等功能。
其中格式转换功能通过识别浏览器请求头 Accept
(如:Accept:image/avif,image/webp,...
),智能下发 AVIF/WebP 等格式图片,以实现更优的压缩率和更快的加载速度。这对开发而言是符合标准且无需额外工作量的终极方案,但该功能尚未普及,因此本文将介绍其他实现相同效果的方式。
AVIF/WebP 简介
WebP 格式
WebP(Web Picture Format)是由 Google 推出的一种现代图片格式,提供有损和无损压缩两种模式。与传统的 PNG 和 JPG 格式相比,WebP 在保持相同视觉质量的情况下,可显著减少文件大小:
- 相比 PNG,WebP 无损压缩可减少 26% 的文件大小;
- 相比 JPG,WebP 有损压缩可减少 25-34% 的文件大小。Next.js + AI-SDK + DeepSeek:3 分钟建设属于你的 AI 问答 Demo
WebP 还支持动画和透明通道,是 GIF 和 PNG 的理想替代方案。目前,WebP 已得到所有现代浏览器的支持(IE 浏览器和部分旧版本移动端浏览器除外)。
AVIF 格式
AVIF(AV1 Image File Format)是基于 AV1 视频编码的新一代图片格式,压缩效率高于 WebP:
- 相比 WebP,AVIF 可减少约 20% 的文件大小;
- 相比 PNG/JPG,AVIF 可减少约 50% 的文件大小。
AVIF 支持高动态范围(HDR)和广色域,色彩表现更丰富。但目前 AVIF 的浏览器支持度弱于 WebP,主要在较新版本的 Chrome、Firefox 和 Opera 等主流浏览器中可用。
在实际使用中,可通过调整压缩参数进一步提升压缩率,以下是兼容性汇总图:
使用 Picture 标签实现图片优化
Picture 标签应用
HTML5 的<picture>
标签允许我们为不同的显示场景提供多个图片源,浏览器会根据当前环境自动选择最合适的图片进行加载。其基本结构如下:
<picture> <source srcset="image.avif" type="image/avif" /> <source srcset="image.webp" type="image/webp" /> <img src="image.png" alt="img" /> </picture>
在这个结构中,浏览器会按照以下顺序进行判断:
- 首先检查是否支持 AVIF 格式,若支持则加载
image.avif
; - 若不支持 AVIF,则检查是否支持 WebP 格式,若支持则加载
image.webp
; - 若以上两种格式均不支持,则回退到传统的
image.png
。
已知问题
虽然<picture>
的兜底策略比较完善(即使 AVIF/WebP 格式或<picture>
/<source>
标签不被浏览器支持,仍可降级到<img>
处理),但因各浏览器厂商实现方式不同,依然存在部分问题。
问题 1:iOS 14.3、14.4 版本的 Safari WebP 兼容性问题
bugs.webkit.org/show_bug.cg…
在 iOS 14.3、14.4 版本的 Safari 中,<picture>
标签会尝试使用 WebP 格式渲染,但图片无法正常显示。需额外通过 JavaScript 检测实际是否支持 WebP 格式,示例如下:
// WebP 支持检测函数 const checkWebP = () => { return new Promise<boolean>((resolve) => { const img = new Image(); img.onload = () => resolve(img.height === 160); img.onerror = () => resolve(false); img.src = "data:image/webp;base64,UklGRh4AAABXRUJQVlA4TBEAAAAvn8AnAAdQiUpUov+BiOh/AAA="; }); }; // 使用示例(简单版,无缓存、占位图等优化机制) const Image = () => { const [supportWebp, setSupportWebp] = useState(false); useEffect(() => { const checkSupportWebP = async () => { const isSupported = await checkWebP(); setSupportWebp(isSupported); }; checkSupportWebP(); }, []); return ( <picture> {supportWebp && <source srcset="image.webp" type="image/webp" />} <img src="image.png" alt="img" /> </picture> ); };
不过站在 2025 年来看,iOS 14.3、14.4 版本的占比可能不到 1%,因此可根据实际情况考虑是否兼容这两个版本的 Safari。
问题 2:部分 Safari 版本同时加载<source>
和<img>
资源 github.com/facebook/re… github.com/vuejs/core/…
问题表现如图:
社区解决方案如下:
// 方案一:把 <img> 标签放在 <source> 标签的前面 <picture> <img src="image.png" alt="img" /> <source srcset="image.webp" type="image/webp" /> </picture>; // 方案二:只保留 img 标签 { isSafari ? ( <img src={supportWebp ? "image.webp" : "image.png"} alt="img" /> ) : ( <picture>{/* some things */}</picture> ); }
问题 3:Firefox 93-112、Safari 16.1-16.3 会将 AVIF 动图解析为静态图片,无动画效果 bugzilla.mozilla.org/show_bug.cg…
github.com/mozilla/sta…
解决方式同问题1,通过 JavaScript 检测是否完整支持 AVIF 格式,以决定是否使用 AVIF 图片。
// AVIF 支持检测函数 const checkAVIF = () => { return new Promise<boolean>((resolve) => { const img = new Image(); img.onload = () => { const supportAvif = img.width === 1; resolve(supportAvif); }; img.onerror = () => resolve(false); // avif 动图 base64 编码,内容省略 img.src = "data:image/avif;base64,..."; }); }; // 使用示例 const Image = () => { const [supportAvif, setSupportAvif] = useState(false); useEffect(() => { const checkSupportAVIF = async () => { const isSupported = await checkAVIF(); setSupportAvif(isSupported); }; checkSupportAVIF(); }, []); return ( <picture> {supportAvif && <source srcset="image.avif" type="image/avif" />} <img src="image.png" alt="img" /> </picture> ); };
ImageX SDK
为解决上述问题并提升代码复用性,我们可能需要自行开发 Image 组件。不过 字节/火山引擎的 ImageX 服务已提供 @volcengine/imagex-react 插件,不仅解决了相关问题且功能更丰富(包括占位图、懒加载、SSR、自适应布局等),可以进行使用。
以下是一个简单的使用示例:
import { ImageXDomains, ImageFormat } from "@/common/consts"; import { ImageLoader, Viewer, ViewerProps } from "@volcengine/imagex-react"; export const Image = (props: ViewerProps) => { const imageLoader: ImageLoader = ({ format, extra }) => { const { domain = "", origin } = extra; /** * 把 https://p1.dailygn.com/obj/g-marketing-act-assets/static/media/bg.png * 转换为 https://p1.dailygn.com/img/g-marketing-act-assets/static/media/bg.png~tplv-obj.avis/awebp */ if (ImageXDomains.includes(domain)) { const { pathname } = new URL(origin); const formatSrc = pathname.replace(/^/obj//, "/img/"); return `//${domain}${formatSrc}~tplv-obj.${format}`; } return origin; }; return ( <Viewer loader={imageLoader} formats={[ImageFormat.Avif, ImageFormat.Webp]} {...props} /> ); };
输出 HTML 结构:
<picture> <source type="image/avif" srcset="//p1.dailygn.com/img/g-marketing-act-assets/static/media/bg.png~tplv-obj.avis"> <source type="image/webp" srcset="//p1.dailygn.com/img/g-marketing-act-assets/static/media/bg.png~tplv-obj.awebp"> <img src="//p1.dailygn.com/img/g-marketing-act-assets/static/media/bg.png~tplv-obj.image" > </picture>
通过 imageLoader
函数,我们可以动态生成图片 URL,以便通过 CDN 下发不同格式、宽度、质量的图片资源。即使在没有使用 ImageX 服务的情况下,也能通过 format
参数适配已有的图片资源。
图片优化结果
通过上述优化,该活动的图片体积显著降低,加载速度也明显加快,具体数据如下:
|
|
|
---|
压缩率及加载速度汇总:
格式 | 图片大小(KB / MB) | 压缩率 | 加载耗时(4G) | 加载速度提升 |
---|---|---|---|---|
PNG | 12506KB / 12.21MB | -- | 18.37s | -- |
WebP | 7355KB / 7.18MB | 41% | 13.3s | 27.6% |
AVIF | 4442KB / 4.33MB | 64% | 10.79s | 41.3% |
总结与思考
随着新技术的发展,图片优化方式也逐渐多种多样,但目前还没有普及的银弹方案。前端开发仍然要了解相关技术细节及坑点,以便实现可靠的程序。
通过 AVIF/WebP 等现代格式的应用及浏览器兼容性检测,可以在保持图片质量的同时,将体积减少约 50%,明显提升加载速度。
在实际应用中,还可以结合多格式降级策略、懒加载及 CDN 优化等手段,进一步提升加载速度与用户体验,并解决在不同浏览器环境下的兼容性问题。
更多推荐
所有评论(0)