一、問題現象
在移動端web開發中,UI設計稿中設置邊框為1像素,前端在開發過程中如果出現border:1px,測試會發現在高清屏機型中,1px會比較粗,即是較經典的移動端1px像素問題。
二、產生原因
高清屏(retina屏)是指高dpr的設備,其物理像素的密度更大。又分為有兩倍屏,三倍屏。
dpr:物理像素/css像素(邏輯像素)
在普通屏,1個css像素對應1個物理像素;2倍屏中,一個css像素對應4個物理像素;三倍屏中則是9個。
按照這樣的置換規則后一張相同的圖片在不同的設備上才會顯示相同的大小。
兩倍屏下用兩排像素去展示1px的線,自然會比普通屏中用一排像素去展示看起來更粗。
三、兩倍屏解決方案
1、0.5px
在IOS8+
,蘋果系列都已經支持0.5px
了,可以借助媒體查詢來處理。
/*這是css方式*/ .border { border: 1px solid #999 } @media screen and (-webkit-min-device-pixel-ratio: 2) { .border { border: 0.5px solid #999 } } /*ios dpr=2和dpr=3情況下border相差無幾,下面代碼可以省略*/ @media screen and (-webkit-min-device-pixel-ratio: 3) { .border { border: 0.333333px solid #999 } }
IOS7
及以下和Android
等其他系統里,0.5px
將會被顯示為0px
。那么我們就需要想出辦法解決。
解決方案是通過JavaScript
檢測瀏覽器能否處理0.5px
的邊框,如果可以,給html
標簽元素添加個class
。
if (window.devicePixelRatio && devicePixelRatio >= 2) { var testElem = document.createElement('div'); testElem.style.border = '.5px solid transparent'; document.body.appendChild(testElem); } if (testElem.offsetHeight == 1) { document.querySelector('html').classList.add('hairlines'); } document.body.removeChild(testElem); } // 腳本應該放在body內,如果在里面運行,需要包裝 $(document).ready(function() {})
然后,極細的邊框樣式就容易了:
div { border: 1px solid #bbb; } .hairlines div { border-width: 0.5px; }
優點:簡單,不需要過多代碼。
缺點:無法兼容安卓設備、 iOS 7
及以下設備。
2、偽類+transform
偽元素::after
或::before
是獨立於當前元素,可以單獨對其縮放而不影響元素本身的縮放。
<div class="border-1px">cell</div> .border-1px { width: 100px; height: 100px; } /*全部邊框*/ .border-1px:after { content: ''; position: absolute; box-sizing: border-box; top: 0; left: 0; width: 200%; height: 200%; border: 1px solid #000; border-radius: 4px; -webkit-transform: scale(0.5); transform: scale(0.5); -webkit-transform-origin: top left; }
優點:所有場景都能滿足,支持圓角(偽類和本體類都需要加border-radius)。
缺點:代碼量也很大,對於已經使用偽類的元素(例如clearfix),可能需要多層嵌套。
3、viewport + rem
同時通過設置對應viewport
的rem
基准值,這種方式就可以像以前一樣輕松愉快的寫1px了。
在devicePixelRatio = 2
時,設置meta
:
<meta name="viewport" content="width=device-width,initial-scale=0.5, maximum-scale=0.5, minimum-scale=0.5, user-scalable=no">
在devicePixelRatio = 3
時,設置meta
:
<meta name="viewport" content="width=device-width,initial-scale=0.3333333333333333, maximum-scale=0.3333333333333333, minimum-scale=0.3333333333333333, user-scalable=no">
優點:所有場景都能滿足,一套代碼,可以兼容基本所有布局。
缺點:老項目修改代價過大,只適用於新項目。
4、border-image以及background-image
將圖片設置為邊框
優點:可以設置單條,多條邊框,沒有性能瓶頸的問題;
缺點:修改顏色麻煩, 需要替換圖片;圓角需要特殊處理,並且邊緣會模糊。
使用border-image
每次都要去調整圖片,可以借助於PostCSS
的插件postcss-write-svg
來幫助我們。
5、box-shadow
可以使用box-shadow來模擬邊框
.border-1px { width: 100px; height: 100px; box-shadow: inset 0px -1px 1px -1px #c8c7cc; }
優點:代碼量少,可以滿足所有場景
缺點:邊框有陰影,顏色變淺
補充:
box-shadow: none | inset(可選值,不設置,為外投影,設置,為內投影) x-offset(陰影水平偏移量,正方向為right) y-offset(陰影垂直偏移量,正方向為bottom) blur-radius(陰影模糊半徑,為正,0為無模糊效果,值越大,越模糊) spread-radius(陰影擴展半徑,可正可負) color
屬性值描述:
1.陰影類型:此參數可選,默認的投影方式是外陰影;如果取其唯一值“inset”,就是將外陰影變成內陰影
2.X-offset:是指陰影水平偏移量,其值可正可負,正值,則陰影在對象的右邊,負值,陰影在對象的左邊
3. Y-offset:是指陰影的垂直偏移量,其值也可以是正負值,正值,陰影在對象的底部,負值時,陰影在對象的頂部
4.陰影模糊半徑:此參數是可選,只能為正值,如果其值為0時,表示陰影不具有模糊效果,值越大陰影的邊緣就越模糊
5. 陰影擴展半徑:此參數可選,其值可為正負值,正值,則整個陰影都延展擴大,反之,則縮小
6.陰影顏色:此參數可選,不設定任何顏色時,瀏覽器會取默認色,但各瀏覽器默認色不一樣,特別是在webkit內核下的safari和chrome瀏覽器將無色,也就是透明,建議不要省略此參數。