如何解決移動(dòng)端 Retina 屏 1px 像素問題 ?
回復(fù)交流,加入前端編程面試算法每日一題群
什么導(dǎo)致了 1px 問題?
在移動(dòng)端 Web 開發(fā)中,UI 設(shè)計(jì)稿中設(shè)置邊框?yàn)?1 像素,前端在開發(fā)過程中如果出現(xiàn) border:1px ,測(cè)試會(huì)發(fā)現(xiàn)在 Retina 屏機(jī)型中,1px 會(huì)比較粗,即是較經(jīng)典的移動(dòng)端 1px 像素問題。
以 iphone6 為例,iphone6 的屏幕寬度為 375px ,設(shè)計(jì)師做的視覺稿一般是750px ,也就是 2x ,這個(gè)時(shí)候設(shè)計(jì)師在視覺稿上畫了 1px 的邊框,于是你就寫了 border:1px ,so...1px邊框問題產(chǎn)生了。
對(duì)設(shè)計(jì)師來說它的 1px 是相對(duì)于 750px 的(物理像素),對(duì)你來說你的 1px 是相對(duì)于 375px 的(css像素),實(shí)際上你應(yīng)該是 border:0.5px 。
如何解決?
| 方案 | 優(yōu)點(diǎn) | 缺點(diǎn) |
|---|---|---|
| 0.5px實(shí)現(xiàn) | 代碼簡(jiǎ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)簡(jiǎ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 將會(huì)被顯示為 0px 。所以我們需要通過 JS 檢測(cè)瀏覽器能否處理 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):簡(jiǎ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 對(duì)文檔進(jìn)行修改,所以性能上有一定影響 -
會(huì)對(duì)項(xiàng)目中所有使用 rem單位的對(duì)象進(jìn)行影響。如果是老項(xiàng)目,則會(huì)全部更改 css 樣式(不適合老項(xiàng)目改造)
偽元素 + transform 實(shí)現(xiàn)
為什么用偽元素? 因?yàn)閭卧?nbsp;::after 或 ::before 是獨(dú)立于當(dāng)前元素,可以單獨(dú)對(duì)其縮放而不影響元素本身的縮放
基于 media 查詢判斷不同的設(shè)備像素比對(duì)線條進(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)?nbsp;svg 是矢量圖形,它的 1px 對(duì)應(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)簡(jiǎn)單,可以實(shí)現(xiàn)圓角, -
缺點(diǎn):需要學(xué)習(xí) svg語法
總結(jié)
綜上,推薦使用:
-
偽元素 + transform 實(shí)現(xiàn) -
svg 實(shí)現(xiàn) -
新項(xiàng)目可以嘗試使用 viewport方案
解決移動(dòng)端 Retina 屏 1px 像素問題
來自:https://github.com/Advanced-Frontend/Daily-Interview-Question/issues/513
最后
號(hào)內(nèi)回復(fù):
120 套模版
