图片模糊到清晰效果本质是CSS过渡实现的视觉占位,需设display:block、监听load事件并用.loaded类触发filter/opacity过渡,避免内联元素兼容性问题及过渡失效。
图片从模糊变为清晰的加载效果,本质上是借助 filter:blur() + opacity 与 CSS 过渡组合形成「视觉占位+渐进呈现」,并不能真正控制图片解码或加载时机;只有图片完成加载后,它才会生效。
<img> 使用 filter:blur(5px) + transition 未必有效常见表现包括图片瞬间变清晰而没有过渡,或者模糊状态根本未被渲染。其原因共有三点:
<img> 默认属于内联元素,filter 内联元素必须显式设,因为其过渡在部分浏览器中的表现并不稳定,旧版 Safari 尤其如此 display: block 或 inline-block
blur 浏览器可能不处理该值对应的优化,src 为 data URL 或本地路径时尤其容易出现load 事件,模糊类就被提前移除,因而丢失过渡img.addEventListener('load', ...) 触发类的切换只有等待图片真实加载完成后再启动过渡,才能避免 blur → none 动画失效。推荐采用以下结构:
<img src="photo.jpg" class="blur-up" alt="">
在 CSS 中设置初始状态与过渡状态:
立即学习“前端免费学习笔记(深入)”;
.blur-up { filter: blur(6px); opacity: 1; transition: filter 0.4s cubic-bezier(0.22, 0.61, 0.36, 1), opacity 0.4s cubic-bezier(0.22, 0.61, 0.36, 1); /* 必须加 display,否则 Safari 可能不触发 filter 过渡 */ display: block;}.blur-up.loaded { filter: blur(0); opacity: 1;}
由 JS 在加载完成后添加类:
document.querySelectorAll('img.blur-up').forEach(img => { if (img.complete) { img.classList.add('loaded'); } else { img.addEventListener('load', () => img.classList.add('loaded')); }});
opacity 是否同时加入过渡,要根据是否需要淡入效果决定仅从模糊转为清晰时,opacity 可以维持 1;不过添加 opacity 「渐进加载」的视觉直觉更符合这种过渡,同时图片尺寸未确定引起的布局抖动也能被遮住:
width/height 属性或 CSS),只需过渡 filter
opacity,并为容器设置 min-height 以防止内容向上跳动opacity: 0 → 1,应从 1 → 1开始(即保持不透明度不变),否则会额外产生一次淡入,与模糊效果不协调filter: blur() 硬件加速无法启用,并可能在 iOS 13 以下或低端 Android 设备上造成卡顿。可采用的稳妥方案是:
blur 设置过大(>8px),优先使用 4px–6px
filter 的老浏览器(IE / iOS <9),添加 @supports (filter: blur(0)) 包裹相关过渡规则will-change: filter ——多数场景的实测结果是不使用反而更稳定,因为它可能带来额外重绘开销真正的难点,是确保模糊状态在首帧中稳定呈现,而非等 JS 加载后再补充——这需要综合考虑 loading="lazy" 的时机、资源优先级以及渲染管线节奏,仅依赖 CSS 过渡无法实现。