移动端1px的解决方案

前言

对于前端开发来说,如何完美的还原UI设计图也是体现了开发功底的,设计师对于我们的要求也是越来越高。例如,如何实现移动端边框1px?为什么1px在不同的设备下展示的粗细不一样?

产生原因

说到这里,我们不得不介绍一下DPR(devicePixelRatio) 设备像素比,它是默认缩放为100%的屏幕下,设备像素和css像素的比值。

DPR(设备像素比) = 物理像素 / css像素 

目前比较主流的设备的DPR=2,也有DPR=3的。当我们的DPR为2,也就是2倍屏时,当物理像素(设备像素)为1px的时候,我们的css像素应该是0.5px。当DPR=3,物理像素为1时,css像素应该为1/3px。对于我们的设计图来说,一般情况下,设计稿是按照750来设计的,而我们写css的样式是参考375的屏,所以我们写的css像素应该为设计稿的像素的一半。设计图为1px,我们css像素应该为0.5px,再考虑到设备的像素比,我们写的css应该是0.25px;

解决方案

1、wwdc对ios系统给出的方案

在 WWDC大会上,对ios8+的并且是DPR=2的设备来说,给出来了1px方案,当写 0.5px的时候,就会显示一个物理像素宽度的 border,而不是一个css像素的 border。 所以在iOS下,你可以这样写

border:0.5px solid #E5E5E5

缺点: 只使用于ios8+,安卓不适用(通常3倍屏设备也适用0.5px来解决)

2、 使用边框图片

这个方法在W3CPlus 上的例子讲的非常细致 https://www.w3cplus.com/content/css3-border-image

border: 1px solid transparent;
border-image: url('./../../image/96.jpg') 2 repeat;

3、使用box-shadow

参考MDN 上的这篇就够了https://developer.mozilla.org/zh-CN/docs/Web/CSS/box-shadow

box-shadow: 0  -1px 1px -1px #e5e5e5,   //上边线
            1px  0  1px -1px #e5e5e5,   //右边线
            0  1px  1px -1px #e5e5e5,   //下边线
            -1px 0  1px -1px #e5e5e5;   //左边线

4、使用伪元素

//一条border
.setOnePx{
  position: relative;
  &::after{
    position: absolute;
    content: '';
    background-color: #e5e5e5;
    display: block;
    width: 100%;
    height: 1px; 
    transform: scale(1, 0.5);
    top: 0;
    left: 0;
  }
}

//4条border
.setBorderAll{
     position: relative;
       &:after{
           content:" ";
           position:absolute;
           top: 0;
           left: 0;
           width: 200%;
           height: 200%;
           transform: scale(0.5);
           transform-origin: left top;
           box-sizing: border-box;
           border: 1px solid #E5E5E5;
           border-radius: 4px;
      }
 }

  • 优点:全机型兼容,实现了真正的1px,而且可以圆角。

  • 缺点:暂用了after 伪元素,可能影响清除浮动。 

5、设置viewport的scale值

这个解决方案是利用viewport+rem+js 实现的。

<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不能再方便

  • 缺点:适用于新的项目,老项目可能改动大

 6、通过@midia手写border

.min-device-pixel-ratio(@scale2, @scale3) {
  @media screen and (min-device-pixel-ratio: 2), (-webkit-min-device-pixel-ratio: 2) {
    transform: @scale2;
  }
  @media screen and (min-device-pixel-ratio: 3), (-webkit-min-device-pixel-ratio: 3) {
    transform: @scale3;
  }
}

.border-1px(@color: #DDD, @radius: 2PX, @style: solid) {
  &::before {
    content: "";
    pointer-events: none;
    display: block;
    position: absolute;
    left: 0;
    top: 0;
    transform-origin: 0 0;
    border: 1PX @style @color;
    border-radius: @radius;
    box-sizing: border-box;
    width: 100%;
    height: 100%;
    @media screen and (min-device-pixel-ratio: 2), (-webkit-min-device-pixel-ratio: 2) {
      width: 200%;
      height: 200%;
      border-radius: @radius * 2;
      transform: scale(.5);
    }
    @media screen and (min-device-pixel-ratio: 3), (-webkit-min-device-pixel-ratio: 3) {
      width: 300%;
      height: 300%;
      border-radius: @radius * 3;
      transform: scale(.33);
    }
  }
}

.border-top-1px(@color: #DDD, @style: solid) {
  &::before {
    content: "";
    position: absolute;
    left: 0;
    top: 0;
    width: 100%;
    border-top: 1Px @style @color;
    transform-origin: 0 0;
    .min-device-pixel-ratio(scaleY(.5), scaleY(.33));
  }
}
.border-bottom-1px(@color: #DDD, @style: solid) {
  &::after {
    content: "";
    position: absolute;
    left: 0;
    bottom: 0;
    width: 100%;
    border-bottom: 1Px @style @color;
    transform-origin: 0 0;
    .min-device-pixel-ratio(scaleY(.5), scaleY(.33));
  }
}
.border-left-1px(@color: #DDD, @style: solid) {
  &::before {
    content: "";
    position: absolute;
    left: 0;
    top: 0;
    height: 100%;
    border-left: 1Px @style @color;
    transform-origin: 0 0;
    .min-device-pixel-ratio(scaleX(.5), scaleX(.33));
  }
}

总结:

一般情况下,我们采用移动端新写的项目都采用viewport的scale方法来实现1px的边框,兼容性好。老项目的话建议还是采用伪元素加transform这种方式。

参考文章:

https://juejin.im/post/5d19b729f265da1bb2774865

https://github.com/dengwb1991/owl-ui/blob/master/src/styles/common/border.less

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值