移動端1px線
viewport告訴你1px爲什麼變粗
html的代碼中經常會有這麼一句
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
這句話的意思是當前viewport的寬度爲設備寬度,初始縮放值和最大縮放值都爲1,並禁止了用戶縮放viewport通俗的講是瀏覽器上可用來顯示頁面的區域。而這句話設置的意義是先不需要用戶縮放和橫向滾動條就能正常的查看網站的所有內容;第二,顯示的文字的大小是合適,比如一段14px大小的文字,不會因爲在一個高密度像素的屏幕裏顯示得太小而無法看清,理想的情況是這段14px的文字無論是在何種密度屏幕,何種分辨率下,顯示出來的大小都是差不多的。
還有一個因素也會引起css中px的變化,那就是用戶縮放。例如,當用戶把頁面放大一倍,那麼css中1px所代表的物理像素也會增加一倍;反之把頁面縮小一倍,css中1px所代表的物理像素也會減少一倍。
在早先的移動設備中,屏幕像素密度都比較低,如iphone3,它的分辨率爲320x480,在iphone3上,一個css像素確實是等於一個屏幕物理像素的。後來隨着技術的發展,移動設備的屏幕像素密度越來越高,從iphone4開始,蘋果公司便推出了所謂的Retina屏,分辨率提高了一倍,變成640x960,但屏幕尺寸卻沒變化,這就意味着同樣大小的屏幕上,像素卻多了一倍,這時,一個css像素是等於兩個物理像素的。其他品牌的移動設備也是這個道理。例如安卓設備根據屏幕像素密度可分爲ldpi、mdpi、hdpi、xhdpi等不同的等級,分辨率也是五花八門,安卓設備上的一個css像素相當於多少個屏幕物理像素,也因設備的不同而不同,沒有一個定論。
有一個devicePixelRatio屬性,它的官方的定義爲:設備物理像素和設備獨立像素的比例,也就是 devicePixelRatio = 物理像素 / 獨立像素。我們在css中使用的px就可以看做是設備的獨立像素,所以通過devicePixelRatio,我們可以知道該設備上一個css像素代表多少個物理像素。例如,在Retina屏的iphone上,devicePixelRatio的值爲2,也就是說1個css像素相當於2個物理像素。
所以這就能解釋爲什麼我們在css中設置的1px看上去比較粗了,也就是比如說我們當前的設備設置了width=device-width, initial-scale=1.0並且當前的設備devicePixelRatio爲2,那麼在css設置的1px就相當於物理像素的2px啦。
viewport的寬度可以通過 document.documentElement.clientWidth來獲取
1px解決方法
用小數的px
iOS8已經支持帶小數的px,但是安卓和低版本的iOS不適用,所以在要考慮兼容性的情況下這個解決方案不太可取。
.border { border: 1px solid #999 }
@media screen and (-webkit-min-device-pixel-ratio: 2) {
.border { border: 0.5px solid #999 }
}
@media screen and (-webkit-min-device-pixel-ratio: 3) {
.border { border: 0.333333px solid #999 }
}
上文有提到devicePixelRatio,media query對應devicePixelRatio有個查詢值-webkit-min-device-pixel-ratio,
transform縮放
(示例代碼語法爲scss)
版本1:
@mixin border1pxtop($color: rgb(232, 232, 232)) {
position: relative;
&:before {
content: '';
position: absolute;
background: $color;
left: 0;
top: 0;
width: 100%;
height: 1px;
// dpr 小於2.9視爲2倍屏
@media screen and (-webkit-min-device-pixel-ratio: 2) and (-webkit-max-device-pixel-ratio: 2.9) {
-webkit-transform: scaleY(0.5);
transform: scaleY(0.5);
}
// dpr 大於2.9視爲3倍屏
@media screen and (-webkit-min-device-pixel-ratio: 2.9) {
-webkit-transform: scaleY((1/3));
transform: scaleY((1/3));
}
}
}
版本2:
解釋一下,先給外面的元素定位position:relative,然後給僞元素定位position:absolute,這樣僞元素就相對於外面元素定位,所以需要給僞元素加上left:0,top:0,另外給僞元素設置邊框border:1px,這邊可以定製自己想要的border,包括顏色,上邊框或者右邊框之類的,然後給width:200%,height:200%,這樣就相對於定位的那個元素放大了兩倍,此時再加上 transform: scale(0.5);就可以將寬度、高度都縮放到和相對定位的那個元素一樣大小,另外邊框的寬度也會縮放一倍,達到我們想要的效果。特別是如果要實現圓角的場景這是推薦的寫法。
@mixin border1pxtop2($color: rgb(232, 232, 223)) {
position: relative;
&::before {
pointer-events: none;
content: '';
box-sizing: border-box;
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
-webkit-transform-origin: 0 0;
transform-origin: 0 0;
border-top: 1px solid $color;
@media (-webkit-min-device-pixel-ratio: 2), (min-resolution: 2dppx) {
width: 200%;
height: 200%;
-webkit-transform: scale(0.5);
transform: scale(0.5);
}
@media (-webkit-min-device-pixel-ratio: 3), (min-resolution: 3dppx) {
width: 300%;
height: 300%;
-webkit-transform: scale(0.333333);
transform: scale(0.333333);
}
}
}
用background
@mixin border1pxleft2($color: rgb(232, 232, 232)) {
background-size: 1px 100%;
background-repeat: no-repeat;
background-position: left top;
background-image: linear-gradient(90deg, $color, $color 100%, transparent 0%);
@media screen and (-webkit-min-device-pixel-ratio: 2) and (-webkit-max-device-pixel-ratio: 2.99) {
background-image: linear-gradient(
90deg,
$color,
$color 50%,
transparent 50%
);
}
will-change
transform方法的版本1有在一些機型不奏效的情況,這個時候可以嘗試加上will-change:transform屬性。will-change是css3新增的屬性。這個屬性如果形象一點說,那就是在真正的行爲觸發之前告訴瀏覽器:注意咯,我一會兒要有變化啦,做好準備哦!作爲迴應,瀏覽器會把GPU給拉上,從容應對即將到來的變化。這樣瀏覽器可以在元素屬性真正發生變化之前提前做好對應的優化準備工作。 這種優化可以將一部分複雜的計算工作提前準備好,使頁面的反應更爲快速靈敏。這也應該是我們使用這個屬性的初衷。
但是不得不說想要用好這個屬性並不容易,試想那種全局都開啓will-change的做法,等於是讓瀏覽器的各個元素都隨時GPU渲染加速待命,效果是適得其反的。
下圖數據來自https://caniuse.com/#feat=will-change
will-change的幾個取值:
will-change: auto;
表示沒有特別指定哪些屬性會變化,瀏覽器需要自己去猜,然後使用瀏覽器經常使用的一些常規方法優化。
will-change: scroll-position;
告訴瀏覽器優化改變滾動條的位置的場景,並且這個場景在將來會發生。
will-change: contents;
表示開發者希望在不久後改變元素內容中的某些東西,或者使它們產生動畫。
will-change: ;
比如will-change: transform;will-change: opacity;