移动端 1px 边框的四种方案与各自的坑
设计稿上 1px 的分割线,在高分屏手机上渲染出来粗得像 2px,设计师天天打回。原因是物理像素与 CSS 像素的换算:375px 宽的设计稿在 3 倍屏(DPR=3)上有 1125 物理像素,1 CSS px 等于 3 物理像素,自然显粗。四种主流方案各有利弊,这篇一次说清。
方案一:0.5px 边框。最直接,DPR 为 2 的屏幕上 0.5 CSS px 恰好对应 1 物理像素:
.border-half {
border: 0.5px solid #dcdee0;
}
/* 不支持小数边框的安卓机型兜底 */
@supports not (border-width: 0.5px) {
.border-half { border-width: 1px; }
}
优点是零 hack、支持圆角。缺点是兼容性靠运气,部分安卓浏览器渲染成 0 或 1,且 DPR=3 时 0.5px 是 1.5 物理像素,仍略粗。
方案二:transform 伪元素缩放。利用 scale 把 1px 的伪元素压扁:
.cell { position: relative; }
.cell::after {
content: '';
position: absolute;
left: 0; right: 0; bottom: 0;
height: 1px;
background: #dcdee0;
transform: scaleY(0.5); /* 2 倍屏取 0.5,3 倍屏取 0.33 */
transform-origin: 0 0;
}
@media (-webkit-min-device-pixel-ratio: 3) {
.cell::after { transform: scaleY(0.33); }
}
优点是兼容性最好,我们生产环境跑了四年。缺点也明显:占用伪元素、四条边框的场合代码量翻倍、圆角边框没法这么画。
方案三:viewport 缩放。把整个页面按 DPR 缩放,让 CSS 像素对齐物理像素:
const dpr = window.devicePixelRatio
const scale = 1 / dpr
document.querySelector('meta[name=viewport]').setAttribute(
'content',
`width=device-width, initial-scale=${scale}, user-scalable=no`
)
document.documentElement.style.fontSize = `${dpr * 37.5}px` // rem 配合
优点是全局一次性解决,还能顺带解决 1px 图片模糊。缺点是侵入太大:第三方组件、富文本里的固定像素全会被缩放影响,老项目慎用。
方案四:border-image 或 background 渐变线。用 2px 高的线性渐变背景当边框,上 1px 透明下 1px 实色。维护成本低,但方向写死、改动费劲,现在用得少了。
我们的选型结论:新项目统一方案一加 @supports 兜底,简洁现代;要兼容老安卓机型的 C 端页面继续方案二。另外提醒设计侧:真要极细的线,直接在设计稿里用 0.5px 并和前端约定方案,比事后打回返工省力。
- 点赞
- 收藏
- 关注作者
评论(0)