如何解決移動端 Retina 屏 1px 像素問題 ?
回復(fù)交流,加入前端編程面試算法每日一題群
什么導(dǎo)致了 1px 問題?
在移動端 Web 開發(fā)中,UI 設(shè)計稿中設(shè)置邊框為 1 像素,前端在開發(fā)過程中如果出現(xiàn) border:1px ,測試會發(fā)現(xiàn)在 Retina 屏機型中,1px 會比較粗,即是較經(jīng)典的移動端 1px 像素問題。

以 iphone6 為例,iphone6 的屏幕寬度為 375px ,設(shè)計師做的視覺稿一般是750px ,也就是 2x ,這個時候設(shè)計師在視覺稿上畫了 1px 的邊框,于是你就寫了 border:1px ,so...1px邊框問題產(chǎn)生了。
對設(shè)計師來說它的 1px 是相對于 750px 的(物理像素),對你來說你的 1px 是相對于 375px 的(css像素),實際上你應(yīng)該是 border:0.5px 。
如何解決?
| 方案 | 優(yōu)點 | 缺點 |
|---|---|---|
| 0.5px實現(xiàn) | 代碼簡單,使用css即可 | IOS及Android老設(shè)備不支持 |
| border-image實現(xiàn) | 兼容目前所有機型 | 修改顏色不方便 |
| viewport + rem 實現(xiàn) | 一套代碼,所有頁面 | 和0.5px一樣,機型不兼容 |
| 偽元素 + transform實現(xiàn) | 兼容所有機型 | 不支持圓角 |
| box-shadow模擬邊框?qū)崿F(xiàn) | 兼容所有機型 | box-shadow不在盒子模型,需要注意預(yù)留位置 |
| svg 實現(xiàn) | 實現(xiàn)簡單,可以實現(xiàn)圓角 | 需要學(xué)習(xí) svg 語法 |
0.5px 實現(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)點:簡單,沒有副作用 缺點:支持 iOS 8+,安卓待兼容
使用 border-image 實現(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;
}
}
缺點:更換顏色需要更換圖片,圓角模糊
viewport + rem 實現(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單位就行了
缺點:
通過 JS 對文檔進行修改,所以性能上有一定影響 會對項目中所有使用 rem單位的對象進行影響。如果是老項目,則會全部更改 css 樣式(不適合老項目改造)
偽元素 + transform 實現(xiàn)
為什么用偽元素? 因為偽元素 ::after 或 ::before 是獨立于當(dāng)前元素,可以單獨對其縮放而不影響元素本身的縮放
基于 media 查詢判斷不同的設(shè)備像素比對線條進行縮放:
.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)點:兼容性好,無副作用,推薦使用
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;
缺點:邊框有陰影,顏色淺,同樣也有兼容性問題,Safari 不支持 1px 以下的 box-shadow。
svg 實現(xià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)點:實現(xiàn)簡單,可以實現(xiàn)圓角, 缺點:需要學(xué)習(xí) svg語法
總結(jié)
綜上,推薦使用:
偽元素 + transform 實現(xiàn) svg 實現(xiàn) 新項目可以嘗試使用 viewport方案
解決移動端 Retina 屏 1px 像素問題
來自:https://github.com/Advanced-Frontend/Daily-Interview-Question/issues/513
最后
號內(nèi)回復(fù):
120 套模版