為什么移動端會產生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