如何解決移動端 Retina 屏 1px 像素問題 ?

什么導(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

可以搭配 PostCSSpostcss-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 像素問題

每天三分鐘,進(jìn)階一個(gè)前端小 tip
面試題庫
算法題庫

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末顽铸,一起剝皮案震驚了整個(gè)濱河市茁计,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌谓松,老刑警劉巖星压,帶你破解...
    沈念sama閱讀 218,451評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異鬼譬,居然都是意外死亡娜膘,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,172評論 3 394
  • 文/潘曉璐 我一進(jìn)店門优质,熙熙樓的掌柜王于貴愁眉苦臉地迎上來竣贪,“玉大人军洼,你說我怎么就攤上這事⊙菰酰” “怎么了匕争?”我有些...
    開封第一講書人閱讀 164,782評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長爷耀。 經(jīng)常有香客問我甘桑,道長,這世上最難降的妖魔是什么歹叮? 我笑而不...
    開封第一講書人閱讀 58,709評論 1 294
  • 正文 為了忘掉前任跑杭,我火速辦了婚禮,結(jié)果婚禮上咆耿,老公的妹妹穿的比我還像新娘德谅。我一直安慰自己,他們只是感情好萨螺,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,733評論 6 392
  • 文/花漫 我一把揭開白布窄做。 她就那樣靜靜地躺著,像睡著了一般屑迂。 火紅的嫁衣襯著肌膚如雪浸策。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,578評論 1 305
  • 那天惹盼,我揣著相機(jī)與錄音,去河邊找鬼惫确。 笑死手报,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的改化。 我是一名探鬼主播掩蛤,決...
    沈念sama閱讀 40,320評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼陈肛!你這毒婦竟也來了揍鸟?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,241評論 0 276
  • 序言:老撾萬榮一對情侶失蹤句旱,失蹤者是張志新(化名)和其女友劉穎阳藻,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體谈撒,經(jīng)...
    沈念sama閱讀 45,686評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡腥泥,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,878評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了啃匿。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片蛔外。...
    茶點(diǎn)故事閱讀 39,992評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡蛆楞,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出夹厌,到底是詐尸還是另有隱情豹爹,我是刑警寧澤,帶...
    沈念sama閱讀 35,715評論 5 346
  • 正文 年R本政府宣布矛纹,位于F島的核電站帅戒,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏崖技。R本人自食惡果不足惜逻住,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,336評論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望迎献。 院中可真熱鬧瞎访,春花似錦、人聲如沸吁恍。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,912評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽冀瓦。三九已至伴奥,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間翼闽,已是汗流浹背拾徙。 一陣腳步聲響...
    開封第一講書人閱讀 33,040評論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留感局,地道東北人尼啡。 一個(gè)月前我還...
    沈念sama閱讀 48,173評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像询微,于是被迫代替她去往敵國和親崖瞭。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,947評論 2 355

推薦閱讀更多精彩內(nèi)容