不能直接给body加filter: blur(),因为会模糊所有子元素导致交互失效;正确做法是用position: fixed的::before伪元素承载背景并单独模糊,内容层保持清晰。

为什么不能直接给body加filter: blur()
因为filter: blur()会模糊整个元素及其所有子元素,包括按钮、输入框、文字——用户点不了、输不了、看不见。你想要的只是“背后页面变糊”,不是“整个页面变糊”。常见错误是写.overlay { filter: blur(8px); }却把弹窗也一起糊掉。
必须用伪元素+fixed定位分层实现
核心思路是:用::before伪元素单独承载背景图,再对它应用blur(),而弹窗内容保持清晰。这个伪元素必须脱离文档流,且尺寸精准覆盖目标区域:
-
::before必须设position: fixed(不是absolute),否则滚动时遮罩会移位或被父级overflow: hidden裁掉 - 必须显式写
inset: 0(或top: 0; right: 0; bottom: 0; left: 0),仅靠width: 100vw; height: 100vh在iOS Safari中会漏底 -
background-image不能靠继承,必须在伪元素上直接写死,比如background: url(...) center/cover -
z-index: -1确保它在内容之下,但别用z-index: -999——部分浏览器对负数z-index渲染不可靠
移动端模糊半径要克制
iOS Safari对blur()有硬性限制:超过blur(12px)可能降级为低精度模糊,甚至动画跳帧。实测安全区间是blur(2px)到blur(8px):
- 小屏设备(如iPhone)建议用
blur(4px)起手,再根据视觉反馈微调 - 避免在
scroll事件里动态改filter值——重绘开销大,容易卡顿;真需要动态模糊,优先用backdrop-filter+rgba()背景 - 如果父容器有
transform或filter,::before会被截断——此时得把伪元素提到body下,用fixed重新锚定
检查是否被裁剪的最快方法
打开 DevTools,选中伪元素,在样式面板里看它的盒子是否完整显示在视口内。如果边缘被切掉,大概率是以下三者之一:
立即学习“前端免费学习笔记(深入)”;
- 父容器设置了
overflow: hidden或transform,导致fixed相对该容器而非视口定位 - 用了
vh单位(如height: 100vh),iOS Safari中它不随地址栏收放更新 -
::before没设content: ""——伪元素无内容时不会渲染,哪怕写了background
最稳兜底方案:把模糊层单独抽成一个div挂到body末尾,用position: fixed; inset: 0;硬控,不依赖任何祖先上下文。


















