一、产生原因
随着移动端的web项目越来越多,设计师的要求也越来越高。在移动端上通过1px实现一条1像素的线时,它并不是真正的1像素,比真正的1像素要粗一点。
那么为什么会产生这个问题呢?主要是跟一个东西有关,DPR(devicePixelRatio) 设备像素比,它是默认缩放为100%的情况下,设备像素和CSS像素的比值。
window.devicePixelRatio=物理像素 /CSS像素
目前主流的屏幕DPR=2 (iPhone 8),或者3 (iPhone 8 Plus)。拿2倍屏来说,设备的物理像素要实现1像素,而DPR=2,所以css 像素只能是 0.5。
一般设计稿是按照750来设计的,它上面的1px是以750来参照的,而我们写css样式是以设备375为参照的,所以我们应该写的0.5px就好了啊! 试过了就知道,iOS 8+系统支持,安卓系统不支持。
二、解决方案
2.1 使用小数点方式
.border { border: 1px solid #999 }
@media screen and (-webkit-min-device-pixel-ratio: 2) {
.border { border: 0.5px solid #999 }
}
@media screen and (-webkit-min-device-pixel-ratio: 3) {
.border { border: 0.333333px solid #999 }
}
- 优点:比较方便
- 缺点:支持iOS 8+,不支持安卓。
2.2 使用伪元素
<span class="border-1px">1像素边框问题</span>
// less
.border-1px{
position: relative;
&::before{
content: "";
position: absolute;
left: 0;
top: 0;
width: 200%;
border:1px solid red;
color: red;
height: 200%;
-webkit-transform-origin: left top;
transform-origin: left top;
-webkit-transform: scale(0.5);
transform: scale(0.5);
pointer-events: none; /* 防止点击触发 */
box-sizing: border-box;
@media screen and (min-device-pixel-ratio:3),(-webkit-min-device-pixel-ratio:3){
width: 300%;
height: 300%;
-webkit-transform: scale(0.33);
transform: scale(0.33);
}
}
}
- 优点:直接通过CSS实现,无论是圆角还是直角都可以实现。
- 缺点:代码量比较多,占有了伪元素。
注意:空元素(不能包含内容的元素)不支持 ::before,::after
- IE 不支持的元素有:img,input,select,textarea。
- FireFox 不支持的元素有:input,select,textarea。
- Chrome 不支持的元素有:input[type=text],textarea。
2.3 使用box-shadow
<span class="border-1px">1像素边框问题</span>
.border-1px{
box-shadow: 0px 0px 1px 0px red inset;
}
- 优点:直接通过CSS实现,无论是圆角还是直角都可以实现。
- 缺点:由于是使用阴影的方式,边框线的颜色会比真实颜色淡一点。
2.4 使用border-image
弄出1px像素边框的实质是弄出0.5px这样的边框,所以我们可以利用类似于这样的图片,使得“border-image-slice”为2,那么实际上边框有一半是透明的,即可得到我们想要的“1px边框”

<div class="test">1像素边框</div>
.test{
border: 1px solid transparent;
border-image: url('./border-1px.png') 2 repeat;
}
- 优点:其实感觉没啥优点。。。
- 缺点:修改颜色麻烦, 需要替换图片;圆角需要特殊处理,并且边缘会模糊
2.5 设置viewport的scale值
根据设备像素设置viewport,代码只需要写正常像素就可以了。
<html>
<head>
<title>1px question</title>
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
<meta name="viewport" id="WebViewport" content="initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no">
<style>
html {
font-size: 1px;
}
* {
padding: 0;
margin: 0;
}
.top_b {
border-bottom: 1px solid #E5E5E5;
}
.a,.b {
box-sizing: border-box;
margin-top: 1rem;
padding: 1rem;
font-size: 1.4rem;
}
.a {
width: 100%;
}
.b {
background: #f5f5f5;
width: 100%;
}
</style>
<script>
var viewport = document.querySelector("meta[name=viewport]");
//下面是根据设备像素设置viewport
if (window.devicePixelRatio == 1) {
viewport.setAttribute('content', 'width=device-width,initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no');
}
if (window.devicePixelRatio == 2) {
viewport.setAttribute('content', 'width=device-width,initial-scale=0.5, maximum-scale=0.5, minimum-scale=0.5, user-scalable=no');
}
if (window.devicePixelRatio == 3) {
viewport.setAttribute('content', 'width=device-width,initial-scale=0.3333333333333333, maximum-scale=0.3333333333333333, minimum-scale=0.3333333333333333, user-scalable=no');
}
var docEl = document.documentElement;
var fontsize = 32* (docEl.clientWidth / 750) + 'px';
docEl.style.fontSize = fontsize;
</script>
</head>
<body>
<div class="top_b a">下面的底边宽度是虚拟1像素的</div>
<div class="b">上面的边框宽度是虚拟1像素的</div>
</body>
</html>
- 优点:全机型兼容,直接写1px不能再方便
- 缺点:适用于新的项目,老项目可能改动大,