解決移動端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">
這種兼容方案相對比較完美,適合新的項目,老的項目修改成本過大。
優點:
- 所有場景都能滿足
- 一套代碼,可以兼容基本所有布局
缺點:
- 老項目修改代價過大,只適用於新項目