1px细线解决方案总结

一、移动端1px变粗的原因

  为什么移动端css里面写了1px, 实际看起来比1px粗,其实原因很好理解:这个px的含义是不一样的。移动端html的header总会有一句

<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">

  这句话定义了本页面的viewport的宽度为设备宽度,初始缩放值和最大缩放值都为1,并禁止了用户缩放。viewport通俗的讲是浏览器上可用来显示页面的区域,这个区域是可能比屏幕大的。根据这篇文章http://www.cnblogs.com/2050/p/3877280.html的分析, 手机存在一个能完美适配的理想viewport,分辨率相差很大的手机的理想viewport的宽度可能是一样的,这样做的目的是为了保证同样的css在不同屏幕下的显示效果是一致的,上面的meta实际上是设置了ideal viewport的宽度。

  以实际举例:iphone3和iphone4的屏幕宽度分别是320px,640px,但是它们的ideal viewport的宽度都是320px,设置了设备宽度后,320px宽的元素都能100%的填充满屏幕宽。不同手机的ideal viewport宽度是不一样的,常见的有320px, 360px, 384px。iphone系列的这个值在6之前都是320px,控制viewport的好处就在于一套css可以适配多个机型。

  看懂的人应该已经明白 1px 变粗的原因了,viewport的设置和屏幕物理分辨率是按比例而不是相同的,移动端 window 对象有个devicePixelRatio属性,它表示设备物理像素和css像素的比例,在retina屏的iphone手机上,这个值为2或3,css里写的 1px 长度映射到物理像素上就有 2px 或 3px 那么长。

  简言之,就是说1px变粗是由于不同的手机有不同的像素密度导致的。如果移动显示屏的分辨率始终是普通屏幕的2倍,1px的边框在devicePixelRatio=2的移动显示屏下会显示成2px,所以在高清屏下看着1px总是感觉变胖了。

  产生原因

  1、设备像素比:dpr=window.devicePixelRatio,也就是设备的物理像素与逻辑像素的比值。

  2、在retina屏的手机上, dpr23css里写的1px宽度映射到物理像素上就有2px3px宽度。例如:iPhone6dpr2,物理像素是750(x轴),它的逻辑像素为375。也就是说,1个逻辑像素,在x轴和y轴方向,需要2个物理像素来显示,即:dpr=2时,表示1个CSS像素由4个物理像素点组成。

二、解决方案

1、用小数来写px值

  IOS8下已经支持带小数的px值,媒体查询 media query 对应 devicePixelRatio 有个查询值-webkit-min-device-pixel-ratio,css可以写成这样

.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 }
}

  如果使用less/sass的话只是加了1句mixin

  缺点: 安卓与低版本IOS不适用,这个或许是未来的标准写法,现在不做指望

2、伪元素 + transform 实现

  对于老项目 伪元素 + transform 是比较完美的方法了。

  原理是把原先元素的 border 去掉,然后利用 :before 或者 :after 重做 border ,并 transform 的 scale 缩小一半,原先的元素相对定位,新做的 border 绝对定位。

  构建1个伪元素,将它的长宽放大到2倍,边框宽度设置为1px,再以transform缩放到50%。

.radius-border{
    position: relative;
}
@media screen and (-webkit-min-device-pixel-ratio: 2){
    .radius-border:before{
        content: "";
        pointer-events: none; /* 防止点击触发 */
        box-sizing: border-box;
        position: absolute;
        width: 200%;
        height: 200%;
        left: 0;
        top: 0;
        border-radius: 8px;
        border:1px solid #999;
        -webkit-transform(scale(0.5));
        -webkit-transform-origin: 0 0;
        transform(scale(0.5));
        transform-origin: 0 0;
    }
}

  需要注意<input type="button">是没有:before, :after伪元素的

  优点: 其实不止是圆角, 其他的边框也可以这样做出来

  缺点: 代码量也很大, 占据了伪元素, 容易引起冲突

3,viewport + rem 实现

  这种兼容方案相对比较完美,适合新的项目,老的项目修改成本过大。

  在devicePixelRatio = 2 时,输出viewport:

  在devicePixelRatio = 3 时,输出viewport:

  优点:所有场景都能满足,一套代码,可以兼容基本所有布局

  缺点:老项目修改代价过大,只适用于新项目

4,使用box-shadow模拟边框

  利用css 对阴影处理的方式实现0.5px的效果。样式设置:

.box-shadow-1px {
    box-shadow: inset 0px -1px 1px -1px #c8c7cc;
}

  优点:代码量少,可以满足所有场景

  缺点:边框有阴影,颜色变浅

上一篇:前端中的物理像素和理论像素 dpi


下一篇:css溢出机制探究