前端不可避免的 1px 问题

前端不可避免的 1px 问题
原因
物理像素 : 物理像素又被称为设备像素,他是显示设备中一个最微小的物理部件。
设备独立像素 : 设备独立像素也称为密度无关像素,可以认为是计算机坐标系统中的一个点,这个点代表一个可以由程序使用的虚拟像素(比如说CSS像素),然后由相关系统转换为物理像素。
设备像素比 :设备像素比简称为dpr,其定义了物理像素和设备独立像素的对应关系。它的值可以按下面的公式计算得到:设备像素比 = 物理像素 / 设备独立像素
在 Retina 屏的手机上 dpr 为 2 或 3,css 里写的 1px 长度映射到物理像素上就有 2px 或 3px 那么长,所以显示出来会比较粗 。

解决方案
方法一 : 用小数写px值
实现 :
.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 }
}
缺点 : IOS8下已经支持带小数的 px 值,但是安卓与低版本 IOS 不适用,这个或许是未来的标准写法,现在不做指望 。
方法二 : border-image
实现 :
使用 border-image 解决 1px 需要一个特定的图片如下:

.border-bottom-1px {
border-width: 0 0 1px 0;
-webkit-border-image: url(linenew.png) 0 0 2 0 stretch;
border-image: url(linenew.png) 0 0 2 0 stretch;
}
上面的效果也仅实现了底部边框border-bottom的1px的效果。之所以使用的图片是2px的高,上部分的1px颜色为透明,下部分的1px使用的视觉规定的border颜色 。
缺点 : 不管是只有一边的边框(比如示例中的底部边框),还是上下都有边框,我们都需要经常对图片做相应的处理,除些之外,如果边框的颜色做了变化,那么也需要对图片做处理。这样也不是一个很好的解决方案 。
方法三 : background渐变
实现 : 背景渐变, 渐变在透明色和边框色中间分割,frozenUI用的就是这种方法,借用它的上边框写法
@media screen and (-webkit-min-device-pixel-ratio: 2){
.ui-border-t {
background-position: left top;
background-image: -webkit-gradient(linear,left bottom,left top,color-stop(0.5,transparent),color-stop(0.5,#e0e0e0),to(#e0e0e0));
}
}
缺点 : 代码量大, 而且需要针对不同边框结构, frozenUI 就定义9种基本样式,而且这只是背景, 这样做出来的边框实际是在原本的border空间内部的,如果元素背景色有变化的样式, 边框线也会消失 ,最后不能适应圆角样式 。
方法四 : 用 box-shadow 模拟边框的
实现 :
.hairlines li {
border: none;
box-shadow: 0 1px 1px -1px rgba(0, 0, 0, 0.5);
}
缺点 :试了下不太好用,颜色不好处理,有阴影出现 。
方法五 : viewport + rem 实现的(淘宝M站)(推荐)
实现 :
在devicePixelRatio = 2 时,输出viewport:
<meta name="viewport" content="initial-scale=0.5, maximum-scale=0.5, minimum-scale=0.5, user-scalable=no">
在devicePixelRatio = 3 时,输出viewport
<meta name="viewport" content="initial-scale=0.3333333333333333, maximum-scale=0.3333333333333333, minimum-scale=0.3333333333333333, user-scalable=no">
缺点 : 个人感觉为了做个 border 多准备两套样式,还得动态改变 viewport ,有点费劲 。
方法六 : 伪类 + transform(weui)(推荐)
实现 : 原理是把原先元素的 border 去掉,然后利用 :before 或者 :after 重做 border ,并 transform 的 scale 缩小一半,原先的元素相对定位,新做的 border 绝对定位
上边距:
.hairlines li{
position: relative;
line-height:30px;
border:none;
}
.hairlines li:after{
content: ' ';
position: absolute;
left: 0;
background: #000;
width: 100%;
height: 1px;
-webkit-transform: scaleY(0.5);
transform: scaleY(0.5);
-webkit-transform-origin: 0 0;
transform-origin: 0 0;
}
四边距:
.hairlines li{
position: relative;
line-height:30px;
margin-bottom: 20px;
border:none;
}
.hairlines li:after{
content: ' ';
position: absolute;
top: 0;
left: 0;
border: 1px solid #000;
-webkit-box-sizing: border-box;
box-sizing: border-box;
width: 200%;
height: 200%;
-webkit-transform: scale(0.5);
transform: scale(0.5);
-webkit-transform-origin: left top;
transform-origin: left top;
}

浙公网安备 33010602011771号