box-shadow在Retina屏上画边框必然发虚,因其本质是亚像素模糊滤镜而非物理像素对齐方案;1px偏移与模糊半径在DPR≥2时被映射为多个物理像素,触发插值渲染,导致边缘毛边、泛白、抖动,且不支持border-radius衔接、无法精准控制整数像素落点。

直接用 box-shadow 在 Retina 屏上画边框,几乎必然发虚——它本质是亚像素模糊滤镜,不是物理像素对齐方案。
为什么 box-shadow: 0 1px 1px -1px 在高 DPR 下会糊
这个写法常被当作“1px 边框替代”,但它依赖浏览器对阴影的抗锯齿渲染。在 window.devicePixelRatio === 2 或 3 时,1px 偏移和 1px 模糊半径会被映射为 2 或 3 物理像素,导致边缘插值、颜色扩散、边界不锐利。Safari 尤其明显,同一段 CSS 在 Chrome 模拟器里看着还行,真机上就是灰蒙蒙一条带。
常见错误现象:
- 边框线边缘有毛边、泛白或色阶过渡
- 多个相邻元素的 shadow 汇聚处出现重影或加粗
- 滚动或 transform 动画中,shadow 位置轻微抖动(sub-pixel 渲染未对齐)
box-shadow 不适合当边框用的三个硬限制
它不是绘制边界,而是投射模糊投影。你无法控制它是否落在整数物理像素上,也无法让它响应 border-radius 的圆角衔接逻辑。
立即学习“前端免费学习笔记(深入)”;
-
blur值永远触发插值,哪怕设成0,只要spread或偏移非整数物理像素,就糊 - 安卓 WebView 和旧版 iOS Safari 对
box-shadow的 sub-pixel 处理极不稳定,inset更容易错位 - 无法与
border-image或伪元素方案共存,叠加后层级和裁剪行为不可控
真机可用的替代方案:用 linear-gradient 模拟单边
这是目前最轻量、兼容性最好、且能严格对齐物理像素的方案。核心是绕过 border 渲染链,用背景图层“画线”。
- 下边框写法:
background: linear-gradient(to bottom, #ccc 50%, transparent 50%) no-repeat bottom / 100% 1px - 必须加
background-size: 100% 1px,否则 DPR=3 时默认拉伸到 3px 高 - 要支持圆角?别在 gradient 上加
border-radius,给父容器设overflow: hidden+border-radius,让线被裁切 - 四边边框慎用:
background: linear-gradient(#ccc, #ccc) no-repeat只能覆盖单边;四边需拼四个 background-layer,维护成本陡增
DPR ≥ 3 时 linear-gradient 仍发虚怎么办
因为 1px 背景高度在 DPR=3 下实际占 3 物理像素,而渐变停靠点(50%)落在 1.5 物理像素线上,触发插值。此时必须动态缩放背景尺寸:
- 用 JS 注入
data-dpr="3"到标签 - CSS 中写:
[data-dpr="3"] .hairline-bottom { background-size: 100% 0.333px; } - 注意:SCSS 不能用
calc(1px / $dpr)编译,那是静态计算;必须靠运行时 JS 注入类名或属性 - 更稳兜底:改用
box-shadow: 0 1px 0 0 #ccc(blur: 0),虽不如伪元素精准,但在 DPR=3 下比带 blur 的版本锐利得多
真正容易被忽略的是:所有这些方案都依赖父容器没有 transform 或 perspective,否则背景定位和缩放锚点会失准。如果用了 will-change: transform,务必在伪元素或背景层上加 backface-visibility: hidden 防止图层合并导致像素混叠。


















