什么導(dǎo)致了 1px 問題绒极?
在移動端 Web 開發(fā)中,UI 設(shè)計(jì)稿中設(shè)置邊框?yàn)?1 像素蔬捷,前端在開發(fā)過程中如果出現(xiàn) border:1px
垄提,測試會發(fā)現(xiàn)在 Retina 屏機(jī)型中,1px 會比較粗周拐,即是較經(jīng)典的移動端 1px 像素問題铡俐。
以 iphone6 為例,iphone6 的屏幕寬度為 375px 妥粟,設(shè)計(jì)師做的視覺稿一般是750px 审丘,也就是 2x ,這個(gè)時(shí)候設(shè)計(jì)師在視覺稿上畫了 1px 的邊框勾给,于是你就寫了 border:1px
滩报,so...1px邊框問題產(chǎn)生了。
對設(shè)計(jì)師來說它的 1px
是相對于 750px
的(物理像素)播急,對你來說你的 1px
是相對于 375px
的(css像素)脓钾,實(shí)際上你應(yīng)該是 border:0.5px
。
如何解決桩警?
方案 | 優(yōu)點(diǎn) | 缺點(diǎn) |
---|---|---|
0.5px實(shí)現(xiàn) | 代碼簡單可训,使用css即可 | IOS及Android老設(shè)備不支持 |
border-image實(shí)現(xiàn) | 兼容目前所有機(jī)型 | 修改顏色不方便 |
viewport + rem 實(shí)現(xiàn) | 一套代碼,所有頁面 | 和0.5px一樣,機(jī)型不兼容 |
偽元素 + transform實(shí)現(xiàn) | 兼容所有機(jī)型 | 不支持圓角 |
box-shadow模擬邊框?qū)崿F(xiàn) | 兼容所有機(jī)型 | box-shadow不在盒子模型沉噩,需要注意預(yù)留位置 |
svg 實(shí)現(xiàn) | 實(shí)現(xiàn)簡單捺宗,可以實(shí)現(xiàn)圓角 | 需要學(xué)習(xí) svg 語法 |
0.5px 實(shí)現(xiàn)
.border-1px { border: 1px solid #999 }
@media screen and (-webkit-min-device-pixel-ratio: 2) {
.border-1px { border: 0.5px solid #999 }
}
/* dpr=2 和 dpr=3 情況下 border 相差無幾,下面代碼可以省略*/
@media screen and (-webkit-min-device-pixel-ratio: 3) {
.border-1px { border: 0.333333px solid #999 }
}
但在 IOS7
及以下和 Android
等其他系統(tǒng)里川蒙,0.5px
將會被顯示為 0px
蚜厉。所以我們需要通過 JS 檢測瀏覽器能否處理 0.5px
的邊框
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);
}
- 優(yōu)點(diǎn):簡單,沒有副作用
- 缺點(diǎn):支持 iOS 8+畜眨,安卓待兼容
使用 border-image 實(shí)現(xiàn)
基于 media
查詢判斷不同的設(shè)備像素比給定不同的 border-image
:
.border-1px{
border-bottom: 1px solid #000;
}
@media only screen and (-webkit-min-device-pixel-ratio:2){
.border_1px{
border-bottom: none;
border-width: 0 0 1px 0;
border-image: url(../img/1pxline.png) 0 0 2 0 stretch;
}
}
缺點(diǎn):更換顏色需要更換圖片昼牛,圓角模糊
viewport + rem 實(shí)現(xiàn)
通過設(shè)置縮放,讓 CSS
像素等于真正的物理像素康聂。
const scale = 1 / window.devicePixelRatio;
const viewport = document.querySelector('meta[name="viewport"]');
if (!viewport) {
viewport = document.createElement('meta');
viewport.setAttribute('name', 'viewport');
window.document.head.appendChild(viewport);
}
viewport.setAttribute('content', 'width=device-width,user-scalable=no,initial-scale=' + scale + ',maximum-scale=' + scale + ',minimum-scale=' + scale);
// 設(shè)置根字體大小
var docEl = document.documentElement;
var fontsize = 10 * (docEl.clientWidth / 320) + 'px';
docEl.style.fontSize = fontsize;
// 在CSS中用rem單位就行了
缺點(diǎn):
- 通過 JS 對文檔進(jìn)行修改贰健,所以性能上有一定影響
- 會對項(xiàng)目中所有使用
rem
單位的對象進(jìn)行影響。如果是老項(xiàng)目恬汁,則會全部更改 css 樣式(不適合老項(xiàng)目改造)
偽元素 + transform 實(shí)現(xiàn)
為什么用偽元素伶椿? 因?yàn)閭卧?::after
或 ::before
是獨(dú)立于當(dāng)前元素,可以單獨(dú)對其縮放而不影響元素本身的縮放
基于 media
查詢判斷不同的設(shè)備像素比對線條進(jìn)行縮放:
.border-1px:before{
content: '';
position: absolute;
top: 0;
height: 1px;
width: 100%;
background-color: #999;
transform-origin: 50% 0%;
}
@media only screen and (-webkit-min-device-pixel-ratio:2){
.border-1px:before{
transform: scaleY(0.5);
}
}
@media only screen and (-webkit-min-device-pixel-ratio:3){
.border-1px:before{
transform: scaleY(0.33);
}
}
注意如果需要滿足圓角氓侧,需要給偽類也加上 border-radius
優(yōu)點(diǎn):兼容性好脊另,無副作用,推薦使用
box-shadow 模擬邊框?qū)崿F(xiàn)
box-shadow: 0 -1px 1px -1px #999,
1px 0 1px -1px #999,
0 1px 1px -1px #999,
-1px 0 1px -1px #999;
缺點(diǎn):邊框有陰影约巷,顏色淺偎痛,同樣也有兼容性問題,Safari 不支持 1px 以下的 box-shadow独郎。
svg 實(shí)現(xiàn)
因?yàn)?svg
是矢量圖形踩麦,它的 1px
對應(yīng)的物理像素就是 1px
可以搭配 PostCSS
的 postcss-write-svg
使用:
@svg border-1px {
height: 2px;
@rect {
fill: var(--color, black);
width: 100%;
height: 50%;
}
}
.svg {
border: 1px solid transparent;
border-image: svg(border_1px param(--color #00b1ff)) 2 2 stretch;
}
編譯后:
.svg { border: 1px solid transparent; border-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' height='2px'%3E%3Crect fill='%2300b1ff' width='100%25' height='50%25'/%3E%3C/svg%3E") 2 2 stretch; }
- 優(yōu)點(diǎn):實(shí)現(xiàn)簡單,可以實(shí)現(xiàn)圓角氓癌,
- 缺點(diǎn):需要學(xué)習(xí)
svg
語法
總結(jié)
綜上谓谦,推薦使用:
- 偽元素 + transform 實(shí)現(xiàn)
- svg 實(shí)現(xiàn)
- 新項(xiàng)目可以嘗試使用
viewport
方案
解決移動端 Retina 屏 1px 像素問題