zoukankan      html  css  js  c++  java
  • 移动端1px解决方案

    移动端1px解决方案

    作者:empty@毛豆前端

    前言

    移动端web项目越来越多,设计师对于UI的要求也越来越高,比如1px 的边框。在高清屏下,移动端的1px 会很粗。 比如,这个是假的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+系统支持,安卓系统不支持。

    二、解决方案

    1、WWDC对iOS统给出的方案

    推荐指数:**

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

    border:0.5px solid #E5E5E5
    复制代码

    可能你会问为什么在3倍屏下,不是0.3333px 这样的?经过我测试,在Chrome上模拟iPhone 8Plus,发现小于0.46px的时候是显示不出来。

    总结:

    • 优点:简单,没有副作用

    • 缺点:支持iOS 8+,不支持安卓。后期安卓follow就好了。

      2、使用边框图片

      推荐指数:**

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

      图片自己随便截图的,建议自己做一张图片

    图片的颜色就是此后border的颜色

    这个方法在W3CPlus 上的例子讲的非常细致 www.w3cplus.com/content/css… 。

    总结:

    • 优点:没有副作用

    • 缺点:border颜色变了就得重新制作图片;圆角会比较模糊。

      3、使用box-shadow实现

      推荐指数:***

      先复习一下box-shadow,看一下MDN 上的这篇就够了developer.mozilla.org/zh-CN/docs/… 。 再看一下效果

    代码是怎样实现的呢?
    box-shadow: 0  -1px 1px -1px #e5e5e5,   //上边线
                1px  0  1px -1px #e5e5e5,   //右边线
                0  1px  1px -1px #e5e5e5,   //下边线
                -1px 0  1px -1px #e5e5e5;   //左边线
    复制代码

    前面两个值 x,y 主要控制显示哪条边,后面两值控制的是阴影半径、扩展半径。 其实方法可以到这个地址线上尝试一下 。

    总结

    • 优点:使用简单,圆角也可以实现

    • 缺点:模拟的实现方法,仔细看谁看不出来这是阴影不是边框。

      4、使用伪元素

      推荐指数:****

      这个方法是我使用最多的,做出来的效果也是非常棒的,直接上代码。

      1 条border

      .setOnePx{
        position: relative;
        &::after{
          position: absolute;
          content: '';
          background-color: #e5e5e5;
          display: block;
           100%;
          height: 1px; /*no*/
          transform: scale(1, 0.5);
          top: 0;
          left: 0;
        }
      }
      复制代码

      可以看到,将伪元素设置绝对定位,并且和父元素的左上角对齐,将width 设置100%,height设置为1px,然后进行在Y方向缩小0.5倍

      4 条border

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

      同样为伪元素设置绝对定位,并且和父元素左上角对其。将伪元素的长和宽先放大2倍,然后再设置一个边框,以左上角为中心,缩放到原来的0.5倍 总结:

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

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

      5、设置viewport的scale值

      推荐指数:*****

      这个解决方案是利用viewport+rem+js 实现的。 参考了网上的一个例子 移动端1像素边框问题的解决方案,自己手动实现了一下。

      效果不错。 上代码
      <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 {
                     100%;
                }
      
                .b {
                    background: #f5f5f5;
                     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不能再方便

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

      三、踩过的坑

      一部血泪史。。。。征服不了UI,只能征服自己。

      1、使用伪元素方法,伪类里面再设置伪元素,可以选择到吗?

      看图,需要改中间的竖线

      上代码
          &:nth-child(2){
            //border-color: #e5e5e5 !important;
              border: 0;
            position: relative;
            &:after{
              position: absolute;
              content: '';
              background-color: #e5e5e5;
              display: block;
               100%;
              height: 1px; /*no*/
              transform: scale(1, 0.5);
              top: 0;
            }
          }
      复制代码

      然而上面代码展示出来的样式是这样的

      为什么中间的竖线没有了?!最初我以为在伪类下面,再写伪元素after,可能会拿不到。看到这里发现,是有after伪元素的,但是好像位置不对,跑到上面去了。我是想要竖线的,到底什么原因呢?最后在安哥的指导找了一种方法解决了这个问题,才明白其中的真相。

      原来是我的width 和 height 设置的有问题,对于竖线,应该是width =1px,height=100%,然后再缩放 X 方向0.5倍,这样竖线就出来了;同样,设置水平线,应该是width=100%,height=1px,然后再缩放Y方向0.5倍

    知道了原因,再也不担心写错了。

    &:nth-child(2){
            position: relative;
            &:after{
              position: absolute;
              content: '';
              top: 0;
              left: 0;
               1px;
              height: 100%;
              transform: scaleX(0.5);
              background: #e5e5e5;
              transform-origin: 0 0;
            }
          }
    复制代码

    这样是可以的,

     &:nth-child(2){
            position: relative;
            &:after{
              content:" ";
              position:absolute;
              top: 0;
              left: 0;
               200%;
              height: 200%;
              transform: scale(0.5);
              transform-origin: left top;
              box-sizing: border-box;
              border-left: 1px solid #E5E5E5;
            }
          }
    复制代码

    这样也是可以的。

    2、为什么还是拿不到伪元素

    我以为知道了上面的方法就可以快快乐乐的写1像素 border 了,然而马上又怀疑自己了。

    上面这个输入框的1像素,需要的所有的border都是1px,我使用了宽高放大200%后再缩小0.5倍的方法。这就奇怪了,同样的方法在别的地方都有效的,为什么在这里不显示了。找了好久,最后找到这篇文章使用 CSS 伪元素需要注意的 ,然后发现:所以不显示的原因找到了,==输入框Textarea不支持伪元素==、 没办法了,伪元素的方法不能用,只能使用其他的方法了。

    四、总结

    总结一下,新项目最好使用的是设置viewport的scale值,这个方法兼容性好,后期写起来方便。老项目的话,改起来可能比较多,用的比较多的方法就是伪元素+transform的方法。 其他的背景图片,阴影的方法毕竟还是不太灵活,而且兼容性不好。

  • 相关阅读:
    003 01 Android 零基础入门 01 Java基础语法 01 Java初识 03 Java程序的执行流程
    002 01 Android 零基础入门 01 Java基础语法 01 Java初识 02 Java简介
    001 01 Android 零基础入门 01 Java基础语法 01 Java初识 01 导学
    001 Android Studio 首次编译执行项目过程中遇到的几个常见问题
    Dora.Interception,为.NET Core度身打造的AOP框架 [2]:以约定的方式定义拦截器
    Dora.Interception,为.NET Core度身打造的AOP框架 [1]:更加简练的编程体验
    监视EntityFramework中的sql流转你需要知道的三种方式Log,SqlServerProfile, EFProfile
    轻量级ORM框架——第二篇:Dapper中的一些复杂操作和inner join应该注意的坑
    轻量级ORM框架——第一篇:Dapper快速学习
    CF888G Xor-MST(异或生成树模板)
  • 原文地址:https://www.cnblogs.com/bamboopanders/p/14641536.html
Copyright © 2011-2022 走看看