解決移動端1px邊框問題的幾種方法
本文介紹了解決移動端1px邊框問題的5種方法。當然了,在這之前先整理了與這些方法相關的知識:物理像素、設備獨立像素、設備像素比和viewport。
物理像素、設備獨立像素和設備像素比
在CSS中我們一般使用px作為單位,需要注意的是,CSS樣式里面的px和物理像素並不是相等的。CSS中的像素只是一個抽象的單位,在不同的設備或不同的環境中,CSS中的1px所代表的物理像素是不同的。在PC端,CSS的1px一般對應着電腦屏幕的1個物理像素,但在移動端,CSS的1px等於幾個物理像素。
物理像素(physical pixel)
物理像素又被稱為設備像素、設備物理像素,它是顯示器(電腦、手機屏幕)最小的物理顯示單位,每個物理像素由顏色值和亮度值組成。所謂的一倍屏、二倍屏(Retina)、三倍屏,指的是設備以多少物理像素來顯示一個CSS像素,也就是說,多倍屏以更多更精細的物理像素點來顯示一個CSS像素點,在普通屏幕下1個CSS像素對應1個物理像素,而在Retina屏幕下,1個CSS像素對應的卻是4個物理像素(參照下文田字示意圖理解)。
設備獨立像素(device-independent pixel)
設備獨立像素又被稱為CSS像素,是我們寫CSS時所用的像素,它是一個抽像的單位,主要使用在瀏覽器上,用來精確度量Web頁面上的內容。
設備像素比(device pixel ratio)
設備像素比簡稱為dpr,定義了物理像素和設備獨立像素的對應關系:設備像素比 = 物理像素 / 設備獨立像素。
簡單點說就是:CSS的1px等於幾個物理像素;除了和屏幕像素密度dpr有關,還和用戶縮放有關系。例如,當用戶把頁面放大一倍,那么CSS中1px所代表的物理像素也會增加一倍;反之把頁面縮小一倍,CSS中1px所代表的物理像素也會減少一倍。關於這點,在文章后面的1px細線問題部分還會講到。

我們可以發現,在同樣的大小下,2dpr的屏幕時普通屏幕像素點的4倍,3dpr的屏幕時普通屏幕像素點的9倍。這就是retina屏幕用了都說好的原因(清晰)。
1px細線問題
在上文我們已經知道,CSS像素為1px寬的直線,對應的物理像素是不同的,可能是2px或者3px,而設計師想要的1px寬的直線,其實就是1物理像素寬。而設計師要的實際1px的邊框就是下面這種情況:

對於CSS而言,可以認為是border: 0.5px;,這是多倍屏下能顯示的最小單位。然而,並不是所有手機瀏覽器都能識別border: 0.5px,有的系統里,0.5px會被當成為0px處理,那么如何1px細線問題呢?
解決方法
1.使用border-image實現
准備一張符合你要求的border-image:

樣式設置:
.border-bottom-1px {
border-width: 0 0 1px 0;
-webkit-border-image: url(linenew.png) 0 0 2 0 stretch;
border-image: url(linenew.png) 0 0 2 0 stretch;
}
上文是把border設置在邊框的底部,所以使用的圖片是2px高,上部的1px顏色為透明,下部的1px使用視覺規定的border的顏色。
優點:
- 可以設置單條、多條表框。
缺點:
- 更換顏色和樣式麻煩,需要更改圖片;
- 某些設備上會模糊。
2.使用background-image實現
background-image 跟border-image的方法一樣,你要先准備一張符合你要求的圖片。然后將邊框模擬在背景上。
樣式設置:
.background-image-1px {
background: url(../img/line.png) repeat-x left bottom;
-webkit-background-size: 100% 1px;
background-size: 100% 1px;
}
優缺點與border-image一樣;
3.多背景漸變實現
與background-image方案類似,只是將圖片替換為css3漸變。設置1px的漸變背景,50%有顏色,50%透明。
樣式設置:
.background-gradient-1px {
background:
linear-gradient(#000, #000 100%, transparent 100%) left / 1px 100% no-repeat,
linear-gradient(#000, #000 100%, transparent 100%) right / 1px 100% no-repeat,
linear-gradient(#000,#000 100%, transparent 100%) top / 100% 1px no-repeat,
linear-gradient(#000,#000 100%, transparent 100%) bottom / 100% 1px no-repeat
}
/* 或者 */
.background-gradient-1px{
background:
-webkit-gradient(linear, left top, right bottom, color-stop(0, transparent), color-stop(0, #000), to(#000)) left / 1px 100% no-repeat,
-webkit-gradient(linear, left top, right bottom, color-stop(0, transparent), color-stop(0, #000), to(#000)) right / 1px 100% no-repeat,
-webkit-gradient(linear, left top, right bottom, color-stop(0, transparent), color-stop(0, #000), to(#000)) top / 100% 1px no-repeat,
-webkit-gradient(linear, left top, right bottom, color-stop(0, transparent), color-stop(0, #000), to(#000)) bottom / 100% 1px no-repeat
}
優點:
- 可以實現單條、多條邊框
- 邊框的顏色隨意設置
缺點:
- 代碼量不少
- 圓角沒法實現
- 多背景圖片有兼容性問題
4.使用box-shadow模擬邊框
利用css 對陰影處理的方式實現0.5px的效果
樣式設置:
.box-shadow-1px {
box-shadow: inset 0px -1px 1px -1px #c8c7cc;
}
優點:代碼少,兼容性好。缺點:邊框有陰影,顏色變淺。
上面四種方式效果並不是太好;
5.偽元素+transform
構建1個偽元素, border為1px, 再以transform縮放到50%。
對於老項目,有沒有什么辦法能兼容1px的尷尬問題了,個人認為偽類+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;
}
四條boder樣式設置:
.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('ul').className = 'scale-1px';
}
優點:可以滿足所有場景,且修改靈活。缺點:對於已使用偽類的元素(例如clearfix)要多層嵌套。
6.viewport + rem 實現
同時通過設置對應viewport的rem基准值,這種方式就可以像以前一樣輕松愉快的寫1px了。
在devicePixelRatio = 2 時,輸出viewport:
<meta name="viewport" content="initial-scale=0.5, maximum-scale=0.5, minimum-scale=0.5, user-scalable=no">
在devicePixelRatio = 3 時,輸出viewport:
<meta name="viewport" content="initial-scale=0.3333333333333333, maximum-scale=0.3333333333333333, minimum-scale=0.3333333333333333, user-scalable=no">
這種兼容方案相對比較完美,適合新的項目,老的項目修改成本過大。
優點:
- 所有場景都能滿足
- 一套代碼,可以兼容基本所有布局
缺點:
- 老項目修改代價過大,只適用於新項目
