# 1px问题

在移动端上,有时候明明设置border: 1px,但对于视觉同事会认为线条比较粗 (如下图)。

# 原因

  1. <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
    • 定义了页面的 viewport宽度 为 设备宽度,初始缩放值 和 最大缩放值 都为 1,同时禁用了用户缩放。
  2. dpr导致。
    • 对于Retina屏,会使用 多个设备像素 去渲染
    .border {
        /* 在 DPR 为 2 时,会用 2 个设备像素 去渲染这个border height */
        border: 1px solid white;
    }
1
2
3
4

更多:像素dpr

综上,是由于设定了缩放值 <meta>,以及 dpr 导致。

# 解决

有 3 个解决方式:媒体查询 + 小数、flexible、伪元素 + transform。

# 媒体查询、小数

不建议:低版本的安卓、IOS(8以下)不兼容小数。

    .border {
        border: 1px solid red;
    }
    @media screen and (-webkit-min-device-pixel-ratio: 2) {
        .border {
            /* 部分机型不兼容小数 */
            border: 0.5px solid red;
        }
    }
    @media screen and (-webkit-min-device-pixel-ratio: 3) {
        .border {
            /* 部分机型不兼容小数 */
            border: 0.33333px solid red;
        }
    }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

# flexible.js

  • 动态计算出 viewportscale 缩放。
scale = 1 / devicePixelRatio

metaElem = document.createElement('meta')
metaElem.setAttribute('name', 'viewport')
metaElem.setAttribute('content', 'initial-scale=' + scale + ', maximum-scale=' + scale + ', minimum-scale=' + scale + ', user-scalable=no')
1
2
3
4
5

# 伪元素 + transform

单独缩放 伪元素 不会影响 元素本身 的缩放。

  • 先判断是否为 “Retina屏” (若是,加上一个class)

  • 原先元素border去掉,利用 伪元素::after 重做border,并缩放 transform: scale(0.5)

// 利用 js 判断是否为 dpr为 2 的Retina 屏
if (window.devicePixelRatio && devicePixelRatio === 2) {
    document.querySelector('div').className = 'scale-1px'
}
1
2
3
4
/* 
 * 父元素 
 * 1. 相对定位
 * 2. 去掉border
 */
.scale-1px {
    position: relative; /* 相对定位 */
    border: none; /* 去掉border */
}

/* 
 * 伪元素 
 * 1. 绝对定位,定位父容器左上角
 * 2. 定义 1px 的 border
 * 3. 将宽高放大 200%
 * 4. 缩小 0.5
 * 5. transform-origin: left top
 */
.scale-1px:after {
    content: ' ';
    position: absolute;
    top: 0;
    left: 0;
    border: 1px solid red;
    width: 200%;
    height: 200%;
    transform: scale(0.5);
    transform-origin: left top; /* 更改元素的转换原点为左上角 */
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29

# 对于圆边框的 1px 解决方案

  • 方法一:采用 伪类 + box-sizing: border-box
  • 方法二:根据设备DPR计算出 viewport 中的 scale 缩放
更新时间: 11/21/2021, 2:45:24 AM