filter blur 在懒加载图片上失效的根本原因是 src 动态替换会重置 css filter 且不触发重绘,需手动强制重排(如 img.offsetheight)或通过 class 切换确保样式重计算。

filter blur 在懒加载图片上失效的常见表现
图片加载完成后 filter: blur(5px) 没反应,或只在首次渲染生效、后续 lazyload 触发后消失——根本原因是浏览器对已设置 filter 的 img 元素,在 src 动态替换(如 img.src = 'xxx.jpg')后,会重置所有 CSS filter 效果,且不触发重绘。
必须手动触发重绘才能让 blur 生效
CSS filter 不是“绑定”在元素上的状态,而是渲染时计算的一次性效果。src 变更后,浏览器认为这是新内容,旧样式(包括 filter)需重新应用。但多数懒加载库(如 lozad、loading="lazy" 原生方案)只改 src,不碰样式。
- 最简方案:改完
src后,强制触发一次重排,例如img.style.opacity = 0.99; img.offsetHeight; img.style.opacity = '' - 更稳妥做法:用
img.classList.add('blurred')配合 CSS 类控制,src 更新后再img.classList.remove('blurred')→ 这样能确保 class 切换触发样式重计算 - 避免直接写内联
style.filter,它容易被后续 JS 覆盖或忽略
移动端 Safari 对 filter + image 的兼容性坑
iOS 15.4 之前,Safari 在 img 上使用 filter: blur() 会导致图片渲染错位、拉伸,甚至白屏;iOS 16+ 改进明显,但仍建议加兜底。
- 检测是否支持:用
CSS.supports('filter', 'blur(1px)'),不支持时 fallback 到opacity: 0.7或背景占位图 - 避免在
picture/source中对每个source单独设 filter,Safari 可能只对最终选中的 source 生效 - blur 值别超过
8px,iOS 渲染压力大,滚动时易掉帧
懒加载 + blur 的最小可行结构示例
不用框架,纯 JS 控制,兼顾可读和实效:
@@##@@
<style>
.lazy { opacity: 0; transition: opacity 0.3s; }
.blurred { filter: blur(6px); }
.loaded { opacity: 1; filter: none; }
</style><script>
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
const img = entry.target;
img.src = img.dataset.src;
// 关键:移除模糊类前先强制重绘
img.classList.remove('blurred');
img.offsetHeight; // 触发 layout
img.classList.add('loaded');
observer.unobserve(img);
}
});
});
document.querySelectorAll('.lazy').forEach(img => observer.observe(img));
</script>
注意 img.offsetHeight 这一行不能省——它不是“为了触发”,而是真实让浏览器同步计算布局,否则 filter: none 可能被跳过。
blur 和懒加载本身都不复杂,难的是它们叠加时浏览器渲染管线的隐式行为。很多人卡在“明明写了 filter,怎么就是不生效”,其实问题不在写法,而在没意识到 src 切换会让 filter 归零。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











