decoding="sync"强制主线程同步解码并阻塞渲染,仅适用于需立即读取naturalWidth/Height布局或严格帧同步的极少数场景,非关键图滥用会显著拖慢首屏与滚动性能。

decoding="sync" 会强制主线程阻塞解码
它不是“让图片更快显示”,而是把解码这一步硬塞进主线程,并且必须等像素数据就绪才继续渲染。哪怕图片 src 已加载完成(img.complete === true),只要解码没完,浏览器就卡住布局和绘制——后续所有 DOM 元素、文字、背景色都会延迟出现。
滚动时内容“突然跳入”是典型表现
这种卡顿在滚动场景下特别明显,因为:
- 主线程被
decoding="sync"占用期间无法响应滚动事件,导致帧率下降 - 图片下方区域原本该随滚动逐步绘制,结果被阻塞,直到解码完成才“啪”一下整体渲染出来
- Lighthouse 的
largest-contentful-paint(LCP)指标会显著变差,尤其在首屏有多个 sync 图时
sync 不等于“关键图必须用”,而是“必须像素级对齐时才用”
多数人误以为 banner 或 logo 是“关键图”,就加 decoding="sync",其实完全没必要。真正需要它的场景极少:
- 用
ctx.drawImage(img, ...)前要立刻读img.naturalWidth做 canvas 尺寸计算 - 动画序列第一帧必须严丝合缝,错一帧就撕裂(比如滤镜预览入口图)
- 服务端返回的图片存在旧浏览器解码兼容问题(如某 WebP 变体在 Chrome 76 下不 sync 就空白)——但应优先修复图片源,而非硬加 sync
现代浏览器默认行为其实是 async,不写 decoding ≠ sync
很多人以为“不写 decoding 就是同步”,这是过时认知。Chrome ≥ 87、Firefox ≥ 78、Safari ≥ 16.4 实际都按异步路径处理未声明 decoding 的 <img>。所以:
- 写了
decoding="sync"是主动要求阻塞 - 不写或写
decoding="auto",浏览器大概率走 async ——auto已沦为占位符,别指望它智能切换 - 想真异步?必须显式写
decoding="async",且配合loading="lazy"、显式宽高、现代格式(WebP/AVIF)才生效



















