移動端1px畫素問題及解決辦法
在移動端web開發中,UI設計稿中設定邊框為1畫素,前端在開發過程中如果出現border:1px,測試會發現在某些機型上,1px會比較粗,即是較經典的移動端1px畫素問題。首選先看一下,pc時代和移動端時代對1px的對比。
一、畫素的理解
畫素是網頁佈局的基礎。一個畫素就是計算機能夠顯示一種特定顏色的最小區域。當裝置尺寸相同但畫素變得更密集時,螢幕能顯示的畫面的過渡更細緻,網站看起來更明快。
1、device pixels
裝置畫素:顯示螢幕的最小物理單位,每個dp包含自己的顏色、高寬等,不可再細分。裝置畫素是在裝置出廠是設定的,裝置一旦造出來就不會變大小和數量。官方在產品說明書上寫的1920x1080就是說的物理畫素。
2、dpi
裝置獨立畫素:dpi(Dots Per Inch,每英寸點數)是一個量度單位,指每一英寸長度中,取樣、可顯示或輸出點的數目。每英寸的畫素,類似於密度,即每英寸的畫素點數量。
3、css pixels
就是CSS和JS所理解的畫素單位,它跟裝置螢幕的畫素沒必然關係,比如windows的桌面顯示器,當你修改顯示器的硬體解析度,比如把1920的解析度改成1024解析度,你會發現網頁裡的圖形和字型變得很大很大的,同樣的顯示器,原本能顯示全部網頁,現在只能顯示一半寬度,也就是說CSS畫素變大了。所以,CSS畫素是可以被硬體和軟體任意調節的單位。css畫素是獨立於裝置邏輯的,用於邏輯上衡量畫素的單位。CSS
//我們通過CSS和javascript程式碼設定的畫素都是邏輯畫素
width:250px;
font-size:22px;
4、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畫素為320px*568px,DPR是2,所以其裝置畫素為640px*1136px
640(px) / 320(px) = 2
1136(px) / 568(px) = 2
640(px)*1136(px) / 320(px)*568(px) = 4
5、視口viewport
瀏覽器上(或者app中的webview)用來顯示網頁的那部分割槽域。業內總結出三個子概念。
佈局視口 layout viewport:
手機一般為了容納為桌面瀏覽器設計的網站,預設佈局viewport寬度遠大於螢幕的寬度,為了讓使用者看到網站全貌,縮小網站。例如,apple一般將viewport寬度定為980px。主要意義是手機廠商不至於讓自家手機變得可笑,在開啟大於980寬度的頁面的時候可以橫向拖動,而不至於擠成一團。可以通過document.documentElement.clientWidth
來獲取。
視覺視口 visual viewport:
螢幕的可視區域,即物理畫素尺寸,可以通過window.innerWidth來獲取。對於iPhone 6 Plus來說,在加了著名程式碼前提下,值是414px,不加的話,值是980px,著名程式碼如果改一改width=device-width, initial-scale=1.5
,這時值是276px。所以它是一個可變的值。
理想視口 ideal viewport:
最適合移動裝置的viewport,ideal viewport的寬度等於移動裝置的螢幕寬度
為了讓viewport能夠等於ideal viewport,一般我們會新增meta標籤。width=device-width,initial-scale=1.0
的時候,視覺視口的大小。對於iPhone 6 Plus來說,是固定值414px。所以,理想視口就等於裝置寬度。
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no"/>
<!--width=device-width:寬度為裝置寬度-->
<!--initial-scale:縮放比為1-->
<!--user-scalable=no:是否允許使用者自定義縮放-->
二、移動端1px解決方案
1、小數值px
解決思路:
<body>
<div id="main" style="border: 1px solid #000000;"></div>
</body>
<script type="text/javascript">
if (window.devicePixelRatio && devicePixelRatio >= 2) {
var main = document.getElementById('main');
main.style.border = '.5px solid #000000';
}
</script>
優點:
簡單,好理解
缺點:
相容性差,目前之餘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, 程式碼比較直觀.
缺點:
大小、顏色更改不靈活
放到PS裡面看邊框,是有點模糊的(因為帶有顏色部分是1px,在retina螢幕上拉伸到2px肯定會有點模糊)
3、background-img漸變
設定1px的漸變背景,50%有顏色,50%透明
.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、CSS3 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和rem結合
viewport結合rem解決畫素比問題
比如在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、:before:after和transform
原理是把原先元素的 border 去掉,然後利用 :before 或者 :after 重做 border ,並 transform 的 scale 縮小一半,原先的元素相對定位,新做的 border 絕對定位。
單條border樣式設定:
.scale-1px{
position: relative;
border:none;
}
.scale-1px:after{
content: '';
position: absolute;
bottom: 0;
background: #000;
width: 100%;
height: 1px;
-webkit-transform: scaleY(0.5);
transform: scaleY(0.5);
-webkit-transform-origin: 0 0;
transform-origin: 0 0;
}
四條border樣式設定:
.scale-1px{
position: relative;
margin-bottom: 20px; border:none;
}
.scale-1px:after{
content: '';
position: absolute;
top: 0;
left: 0;
border: 1px solid #000;
-webkit-box-sizing: border-box;
box-sizing: border-box;
width: 200%;
height: 200%;
-webkit-transform: scale(0.5);
transform: scale(0.5);
-webkit-transform-origin: left top;
transform-origin: left top;
}
結合js來程式碼來判斷是否是Retina屏if(window.devicePixelRatio && devicePixelRatio >= 2){
document.querySelector('div').className = 'scale-1px';
}
優點:
所有場景都能滿足
支援圓角
缺點:
對於已經使用偽類的元素,可能需要多層巢狀
總結
1、0.5px,相信瀏覽器肯定是會慢慢支援的;目前而言,如果能用的話,可以hack一下;
2、陰影,border-img的方案不建議使用
3、背景圖片和縮放可以在專案中配合使用,如單個線條使用縮放,四條框用背景圖片模擬,額,如果要圓角的話,無能無力了
4、建議採用transform和偽類
參考文獻
畫素概念
http://efe.baidu.com/blog/1px-on-retina/
https://link.jianshu.com/?t=https://github.com/amfe/article/issues/17