HTML+CSS34 1px边框问题的解决方案

1px边框问题的解决方案的总结

现象及原因

在移动端开发时,设计图中的1px的边框,如果我们直接在CSS中设置边框的宽度为1px,实际上在设备上显示的并不是1px。这是因为不同的手机有着不同的像素密度,即window.devicePixelRatio属性,它反应的是物理像素与逻辑像素的比值,IPhone6的dpr是2,也就是说,对于IPhone6来说,CSS的1px显示时会显示为2px的像素

当设置为1px的边框时,移动端的显示:

当设置为0.5px的边框时,移动端的显示:

PC端1px的边框:

很明显看出,移动端1px的边框更粗

媒体查询

要想解决这个问题,必须针对不同dpr的设备进行不同的处理,完全不必使用JavaScript,而是可以通过媒体查询实现

1
2
3
4
5
6
7
@media screen and (min-device-pixel-ratio: 2),  (-webkit-min-device-pixel-ratio: 2){
/* 2倍屏 */
}

@media screen and (min-device-pixel-ratio: 3), (-webkit-min-device-pixel-ratio: 3){
/* 3倍屏 */
}

下面的各种处理方法,都是通过媒体查询进行分类处理,只列出2倍屏的处理方法,都省略了媒体查询的代码

解决方法1:伪元素 + tranform: scaleY

这种方法是比较常用,兼容性也比较好的,利用高度为1px的伪元素来模拟边框,在媒体查询中利用tranform: scaleY来进行缩放,需要设置transform: origin(0, 0)保证缩放时伪元素距离父元素的距离

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
h1 {
position: relative;
}

h1:after {
content: '';
display: block;
width: 100%;
height: 1px;
position: absolute;
left: 0;
bottom: 0;
background: red;
transform: scaleY(1);
transform-origin: 0 0;
}

@media screen and (min-device-pixel-ratio: 2), (-webkit-min-device-pixel-ratio: 2) {
h1:after {
transform: scaleY(0.5);
}
}
  • 优点:兼容性好,边框圆角也可以实现
  • 缺点:代码量比较大,占据了伪元素,会引起冲突

解决方法2:0.5px边框

直接将border设置为0.5px

1
2
3
.h1 {
border-bottom: 0.5px solid #000
}
  • 优点:简单直接
  • 缺点:兼容性太差,安卓和低版本的IOS都不支持

解决方法3:伪元素 + liner-gradient + sacle

同样是利用伪元素实现,但是使用了liner-gradient来模拟边框,实际上和第一种方法思路是相同的

1
2
3
4
5
6
7
8
9
10
11
12
h1:after {
display: block;
content: '';
height: 1px;
background: linear-gradient(0, #fff, #000);
}

@media screen and (min-device-pixel-ratio: 2), (-webkit-min-device-pixel-ratio: 2) {
h1:after {
transform: scaleY(0.5);
}
}

解决方法4:通过viewport实现

可以使用JavaScript来读取window.devicePixelRatio,根据读取到的值来对<meat>viewport进行改写,当dpr为2时,将页面缩放到原来的一半

1
2
3
4
5
6
7
8
9
10
11
12
13
const dpr = window.devicePixelRatio;

// 创建meta视口标签
const meta = document.createElement('meta')

// 设置name为viewport
meta.setAttribute('name', 'viewport');

// 动态初始缩放、最大缩放、最小缩放比例
meta.setAttribute(
'content',
`width=device-width, user-scalable=no, initial-scale=${1/dpr}, maximum-scale=${1/dpr}, minimum-scale=${1/dpr}`
)

这样做可以直接使用px来定义各处的尺寸,但是就不单单针对边框了,而是针对所有了,需要整体考虑

解决方法4:通过图片模拟

可以使用border-image 或者background-image来加载预先设置好的边框图片

这种方法并不是很理想,因为修改颜色的时候都需要替换图片,并且如果边框有圆角的话也需要对图片特殊处理。

总结

从兼容性、针对性以及可维护性,还是使用伪元素 + tranform: scaleY的第一种方法最为推荐,其他的方法要不是很麻烦,要不是原理相同。有一些文章介绍了七八种,有的能实现,但是实施起来很麻烦,有的根本就不能实现在移动端实现1px,也不知道是我水平太低,还是作者根本没有亲自试验。

参考