移動端1px解決方案

做者:empty@毛豆前端javascript

前言

移動端web項目愈來愈多,設計師對於UI的要求也愈來愈高,好比1px 的邊框。在高清屏下,移動端的1px 會很粗。 好比,這個是假的1像素 php

這個是真的1像素

1、產生緣由

那麼爲何會產生這個問題呢?主要是跟一個東西有關,DPR(devicePixelRatio) 設備像素比,它是默認縮放爲100%的狀況下,設備像素和CSS像素的比值。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+系統支持,安卓系統不支持。html

2、解決方案

一、WWDC對iOS統給出的方案

推薦指數:**

在 WWDC大會上,給出來了1px方案,當寫 0.5px的時候,就會顯示一個物理像素寬度的 border,而不是一個css像素的 border。 因此在iOS下,你能夠這樣寫。前端

border:0.5px solid #E5E5E5
複製代碼

可能你會問爲何在3倍屏下,不是0.3333px 這樣的?通過我測試,在Chrome上模擬iPhone 8Plus,發現小於0.46px的時候是顯示不出來。java

總結:css3

  • 優勢:簡單,沒有反作用git

  • 缺點:支持iOS 8+,不支持安卓。後期安卓follow就行了。github

    二、使用邊框圖片

    推薦指數:**

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

    圖片本身隨便截圖的,建議本身作一張圖片web

圖片的顏色就是此後border的顏色

這個方法在W3CPlus 上的例子講的很是細緻 www.w3cplus.com/content/css…

總結:

  • 優勢:沒有反作用

  • 缺點:border顏色變了就得從新制做圖片;圓角會比較模糊。

    三、使用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 主要控制顯示哪條邊,後面兩值控制的是陰影半徑、擴展半徑。 其實方法能夠到這個地址線上嘗試一下

總結

  • 優勢:使用簡單,圓角也能夠實現

  • 缺點:模擬的實現方法,仔細看誰看不出來這是陰影不是邊框。

    四、使用僞元素

    推薦指數:****

    這個方法是我使用最多的,作出來的效果也是很是棒的,直接上代碼。

    1 條border

    .setOnePx{
      position: relative;
      &::after{
        position: absolute;
        content: '';
        background-color: #e5e5e5;
        display: block;
        width: 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;
               width: 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 僞元素,可能影響清除浮動。

    五、設置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 {
                  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不能再方便

  • 缺點:適用於新的項目,老項目可能改動大

    3、踩過的坑

    一部血淚史。。。。征服不了UI,只能征服本身。

    一、使用僞元素方法,僞類裏面再設置僞元素,能夠選擇到嗎?

    看圖,須要改中間的豎線

    上代碼

    &:nth-child(2){
          //border-color: #e5e5e5 !important;
            border: 0;
          position: relative;
          &:after{
            position: absolute;
            content: '';
            background-color: #e5e5e5;
            display: block;
            width: 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;
          width: 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;
          width: 200%;
          height: 200%;
          transform: scale(0.5);
          transform-origin: left top;
          box-sizing: border-box;
          border-left: 1px solid #E5E5E5;
        }
      }
複製代碼

這樣也是能夠的。

二、爲何仍是拿不到僞元素

我覺得知道了上面的方法就能夠快快樂樂的寫1像素 border 了,然而立刻又懷疑本身了。

上面這個輸入框的1像素,須要的全部的border都是1px,我使用了寬高放大200%後再縮小 0.5倍的方法。
這就奇怪了,一樣的方法在別的地方都有效的,爲何在這裏不顯示了。找了很久,最後找到這篇文章 使用 CSS 僞元素須要注意的 ,而後發現:
因此不顯示的緣由找到了,==輸入框Textarea不支持僞元素==、 沒辦法了,僞元素的方法不能用,只能使用其餘的方法了。

4、總結

總結一下,新項目最好使用的是設置viewport的scale值,這個方法兼容性好,後期寫起來方便。老項目的話,改起來可能比較多,用的比較多的方法就是僞元素+transform的方法。 其餘的背景圖片,陰影的方法畢竟仍是不太靈活,並且兼容性很差。

相關文章
相關標籤/搜索