产生原因
- 设备像素比(window.devicePixelRatio),也就是设备的物理像素与逻辑像素的比值
- 在retina屏的手机, dpr为2或3,css里写的1px宽度映射到物理像素上就有2px或3px宽度。
解决方案
实现1PX边框的方法有很多,各有优缺点,比如通过0.5px、背景图片实现、border-image、postcss-write-svg等实现。本文通过伪类元素+transform、viewport+rem两种方式实现,优点是可以自适应已知的各类手机屏幕,且不存在其它方法存在的变颜色困难、圆角阴影失效问题。
-
伪类元素 + transform
- 优点:所有场景都能满足,支持圆角(伪类和本体类都需要加border-radius)。
- 缺点:对于已经使用伪类的元素(例如clearfix),可能需要多层嵌套。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
.box{
100px;
height: 100px;
position: relative;
}
.box::after{
content:'';
position: absolute;
left: 0;
bottom: 0;
100%;
height: 1px;
background: #000;
}
@media screen and (-webkit-min-device-pixel-ratio: 2) {
.box::after{
transform: scaleY(0.5);
}
}
@media screen and (-webkit-min-device-pixel-ratio: 3) {
.box::after{
transform: scaleY(0.33333);
}
}
</style>
</head>
<body>
<div class="box"></div>
</body>
</html>
-
viewport + rem + js
- 优点:所有场景都能满足,一套代码,可以兼容基本所有布局。
- 缺点:老项目修改代价过大,只适用于新项目。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
.box{
0.5rem;
height: 0.5rem;
border-bottom: 1px solid #000;
}
</style>
</head>
<body>
<div class="box"></div>
<script>
var dpr = window.devicePixelRatio;
var scale = 1 / dpr;
var width = document.documentElement.clientWidth;
var metaNode = document.querySelector('meta[name="viewport"]')
metaNode.setAttribute("content","width=device-width, initial-scale="+scale)
var htmlNode = document.querySelector("html");
htmlNode.style.fontSize = width * dpr +'px';
</script>
</body>
</html>