1. 程式人生 > >移動端1px問題解決方法

移動端1px問題解決方法

為什麼移動端會產生1px問題呢?

UI設計師設計的時候,畫的1px(真實畫素)實際上是0.5px(css)的線或者邊框。但是他不這麼認為,他認為他畫的就是1px的線,因為他畫的稿的尺寸本身就是螢幕尺寸的2倍。假設手機視網膜屏的寬度是320x480寬,但實際尺寸是640x960寬,設計師設計圖的時候一定是按照640x960設計的。但是前端工程師寫程式碼的時候,所有css都是按照320x480寫的,寫1px(css),瀏覽器自動變成2px(真實畫素)。

那麼前端工程師為什麼不能直接寫0.5px(css)呢?因為在老版本的系統裡寫0.5px(css)的話,會被瀏覽器解讀為0px(css),就沒有邊框了。所以只能寫成1px(css),實際在螢幕上顯示出來就是設計師畫的1px(真實畫素)的2倍那麼寬,所以設計師會覺得這個線太粗了,和他的設計稿不一樣。在新版的系統裡,已經開始逐漸支援0.5px(css)這種寫法。所以如果設計師在大圖上設計了一個1px(真實畫素)的線的話,前端工程師直接除以2,寫0.5px(css)就好了。

先上解決方法

1.小數值

div {
    border: 1px solid #000;
}

@media (-webkit-min-device-pixel-ratio: 2) {
  div {
    border: .5px solid #000;
  }
}

缺點: 相容性差,目前只有IOS8+才支援,在IOS7及其以下、安卓系統都是顯示0px。

2.border-image

.border-image-1px {
    border-width: 1px 0px;
    -webkit-border-image: url(border.png) 2 0 stretch;
    border-image: url(border.png) 2 0 stretch;

優點:圖片可以用gif, png, base64多種格式, 以上是上下左右四條邊框的寫法, 需要單一邊框只要定義單一邊框的border, 程式碼比較直觀.
缺點:大小,顏色更改不靈活

3.background-img漸變

.border {
    background:
    linear-gradient(180deg, black, black 50%, transparent 50%) top    left  / 100% 1px no-repeat,
    linear-gradient(90deg,  black, black 50%, transparent 50%) top    right / 1px 100% no-repeat,
    linear-gradient(0,      black, black 50%, transparent 50%) bottom right / 100% 1px no-repeat,
    linear-gradient(-90deg, black, black 50%, transparent 50%) bottom left  / 1px 100% no-repeat;
}

4.box-shadow

.shadow {
        -webkit-box-shadow:0 1px 1px -1px rgba(255, 0, 0, 0.5);
    box-shadow:0 1px 1px -1px rgba(255, 0, 0, 0.5);
}

5.viewport

在devicePixelRatio=2設定meta
<meta name="viewport" content="initial-scale=0.5, maximum-scale=0.5, minimum-scale=0.5, user-scalable=no">
在devicePixelRatio=3設定meta
<meta name="viewport" content="initial-scale=0.3333333333333333, maximum-scale=0.3333333333333333, minimum-scale=0.3333333333333333, user-scalable=no">

6.transform:scale(0.5)

這個方案也是WeUI正在用的,核心思想是使用transform的scale來整體縮放,如果你想畫一條1px的線,就可以直接用

div {
    height: 1px;
      background: #000;
      transform: scaleY(0.5);
      transform-origin: 0 0;
}

理論上在dpr為2時就是scaleY(0.5),在dpr為3時就是scaleY(0.333),但是我注意到WeUI並沒有針對其他dpr的做特殊處理,可能是因為在iPhone6(dpr=2)和iPhone6 Plus(dpr=3)中看起來差別不大吧

如果你想給一個元素加一個1px的邊框可以利用到偽元素,在這個方案下邊框加圓角也很容易實現,具體程式碼如下:

div:after {
  content: " ";
  width: 78px;
  height: 38px;
  border-radius: 4px;
  border: 1px solid #000;
  transform: scale(0.5, 0.5);
  transform-origin: 0 0;
  position: absolute;
}

建議採用transform和偽類

相關知識

1.device pixels
裝置畫素:顯示螢幕的最小物理單位,每個dp包含自己的顏色、高寬等,不可再細分。裝置畫素是在裝置出廠是設定的,裝置一旦造出來就不會變大小和數量。官方在產品說明書上寫的1920x1080就是說的物理畫素。
2.dpi
裝置畫素:顯示螢幕的最小物理單位,每個dp包含自己的顏色、高寬等,不可再細分。裝置畫素是在裝置出廠是設定的,裝置一旦造出來就不會變大小和數量。官方在產品說明書上寫的1920x1080就是說的物理畫素。
3.dpr
裝置畫素比dpr = 裝置畫素 / CSS畫素(某一方向上)
可以通過window.devicePixelRatio獲取裝置的dpr值。一般來說,在桌面的瀏覽器中,裝置畫素比(dpr)等於1,一個css畫素就是代表的一個物理畫素。而在移動端,大多數機型都不是為1,其中iphone的dpr普遍是2和3,那麼一個css畫素不再是對應一個物理畫素,而是2個和3個物理畫素。即我們通常在css中設定的width:1px,對應的便是物理畫素中的2px。手機機型不同,dpr可能不同。

以iphone5為例,iphone5的CSS畫素為320px568px,DPR是2,所以其裝置畫素為640px1136px

640(px) / 320(px)  = 2
1136(px) / 568(px) = 2
640(px)*1136(px) /  320(px)*568(px) = 4