一步搞定移动端1px像素问题

1,939 阅读2分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第4天,点击查看活动详情

原因

css的1px在PC端就是1px; 在移动端就往往就大于 1pxcss的1px在PC端就是1px; 在移动端就往往就大于 1px

第一种方式

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>1px 问题</title>
    <style>
        body {margin:0;padding:19px}
        div { padding:1em;margin:1em;}
        .box1{border-top: 1px solid #000;}
        .box2{border-bottom:1px solid #000;}
    </style>
</head>
<body>
    <div class="box1">
        1px的上边框
    </div>

    <div class="box2">
        0.5px的上边框
    </div>
</body>
</html>

产生的原因

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

解决方式

实现原理:伪元素 + transform 缩放

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>1px 问题</title>
    <style>
        body {margin:0;padding:19px}
        div { padding:1em;margin:1em;}
        .box1{border-top: 1px solid #000;}
        .box2{position: relative;border-bottom:1px solid #000;}
        .box2::after{
            content:'';
            position: absolute;
            left:0;top:0;width: 100%;
            height: 1px; 
            background-color: #000;
            transform: scaleY(0.5);
        }
    </style>
</head>
<body>
    <div class="box1">
        1px的上边框
    </div>

    <div class="box2">
        0.5px的上边框
    </div>
</body>
</html>

伪元素::after::before独立于当前元素,可以单独对其缩放而不影响元素本身的缩放

优点:所有场景都能满足,支持圆角(伪类和本体类都需要加border-radius)。

缺点:代码量也很大,对于已经使用伪类的元素(例如clearfix),可能需要多层嵌套。

第二种方式

同时通过设置对应viewportrem基准值,这种方式就可以像以前一样轻松愉快的写1px了。
devicePixelRatio=2 时,设置meta

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

devicePixelRatio=3 时,设置meta

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

例子:

<!DOCTYPE html>
<html lang="en">
<head>
     <title>移动端1px问题</title>
     <meta http-equiv="Content-Type" content="text/html;charset=UTF-8" />
      <meta name="viewport" id="WebViewport"content="width=device-width,initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no" />
      <style>
          html {
             font-size11px;
          }
       body {
              padding1rem;
          }
          * {
              padding0;
             margin0;
          }
         .item {
              padding1rem;
              border-bottom1px solid gray;
              font-size1.2rem;
          }
      </style>
      <script>
          var viewport = document.querySelector("meta[name=viewport]");
          var dpr = window.devicePixelRatio || 1;
          var scale = 1 / dpr;
          //下面是根据设备dpr设置viewport
          viewport.setAttribute(
             "content", +
              "width=device-width," +
             "initial-scale=" +
              scale +
              ", maximum-scale=" +
              scale +
              ", minimum-scale=" +
              scale +
              ", user-scalable=no"
         );

          var docEl = document.documentElement;
          var fontsize = 10 * (docEl.clientWidth / 320) + "px";
          docEl.style.fontSize = fontsize;
      </script>
  </head>
  <body>
      <div class="item">border-bottom: 1px solid gray;</div>
     <div class="item">border-bottom: 1px solid gray;</div>
  </body>
 </html>

优点:所有场景都能满足,一套代码,可以兼容基本所有布局。
缺点:老项目修改代价过大,只适用于新项目。