本文轉(zhuǎn)載自 Biossun 浪淘沙 的 聊聊一物理像素邊框
本文只是基于「一物理像素邊框」這一主題隨意寫的一些碎碎念品嚣,其中并不會(huì)詳細(xì)講解各種實(shí)現(xiàn)方式及其原理汇恤,如果想要知道這些內(nèi)容臂聋,你在網(wǎng)上可以檢索到很多夕吻,比如大漠的 再談Retina下1px的解決方案 就很不錯(cuò)枷踏。
像素單位
首先啡氢,先聊下我們最常用的 CSS 單位 —— 'px'状囱。
按照 CSS 的規(guī)定,單位 px 應(yīng)當(dāng)是一個(gè)絕對(duì)長(zhǎng)度值倘是;但這里所說的「絕對(duì)」亭枷,并不是指 1px 嚴(yán)格對(duì)等于顯示設(shè)備上的一個(gè)物理像素點(diǎn)(雖然早年間確實(shí)如此),而是應(yīng)當(dāng)約等于 0.0213° 視角投射在屏幕上的長(zhǎng)度(在假設(shè)屏幕距離用戶眼睛為 71cm 的情況下搀崭,1px 應(yīng)約等于 0.26mm)叨粘。
如此定義的目的,是因?yàn)檫@可以確保用戶在正常使用任何顯示設(shè)備時(shí)所看到的內(nèi)容的大小都是大致相同的瘤睹。
只不過升敲,這個(gè)名字卻容易引發(fā)歧義,因?yàn)楫?dāng)我們單獨(dú)說到 'Pixel' 時(shí)轰传,通常所指的是設(shè)備的物理像素點(diǎn)驴党,也就是 'Dot',比如在 iOS 及 Android 系統(tǒng)中获茬,px 所指的都是物理像素港庄。(而對(duì)應(yīng)的,iOS 的 pt 單位及 Android 的 dp 單位倒是與 CSS 中的 px 相似)
為什么需要一物理像素邊框
接著恕曲,我們?cè)僬f回邊框的事鹏氧。
通常,我們?cè)谶M(jìn)行布局和排版時(shí)佩谣,px(CSS)就已經(jīng)足夠使用了把还,幾乎用不到物理像素。但有一種情況下,我們總是會(huì)需要比 1px
更小的長(zhǎng)度值笨篷,這就是邊框瞳秽。
在移動(dòng)端的使用場(chǎng)景中,其屏幕通常距離用戶的眼睛會(huì)比較近率翅,而且一般屏幕設(shè)備的像素密度都會(huì)比較高练俐,因此即便是 1 物理像素的邊框,用戶也能看清而不會(huì)感到費(fèi)力冕臭。另外腺晾,1 物理像素的邊框相比會(huì)更加纖細(xì),在用戶眼中的視覺比重會(huì)更低辜贵,相應(yīng)的會(huì)更加突出內(nèi)容悯蝉。所以在移動(dòng)端,實(shí)現(xiàn) 1 物理像素的邊框通常是有必要的托慨。
實(shí)現(xiàn)
那么鼻由,CSS 中有比 px 更小的長(zhǎng)度單位嗎?抱歉厚棵,沒有蕉世。我們可以在網(wǎng)上找到一些關(guān)于這件事的討論,比如這個(gè)婆硬,但通常沒有結(jié)果狠轻。
所以,我們只能通過各種花招來模擬實(shí)現(xiàn)它彬犯。常見的就有背景漸變向楼、縮小偽元素、border-image 和 0.5px border 及 box-shadow 這幾種谐区,額外的還有像淘寶的 Flexible 方案這種因?yàn)榭s放了整個(gè)頁(yè)面所以順便就實(shí)現(xiàn)了一物理像素邊框的湖蜕。這些方案的具體實(shí)現(xiàn)在網(wǎng)上都有很多,這里不再贅述卢佣。
0.5px border 或 box-shadow
相對(duì)來說重荠,0.5px 邊框和 box-shadow 是這些方案中最容易使用的兩個(gè)箭阶。各用一行代碼就可以實(shí)現(xiàn)虚茶,比如:
.hairline {
border: 0.5px solid #000;
}
/* or */
.hairline {
box-shadow: inset 0 0 0 0.5px #000;
}
不過雖然簡(jiǎn)單,但兼容性卻著實(shí)讓人頭疼仇参。
對(duì)于 0.5px 邊框嘹叫,iOS Safari 支持地非常好,目前蘋果移動(dòng)設(shè)備的設(shè)備像素比都是 2x 或 3x诈乒,在這些設(shè)備上罩扇,Safari 都能將 0.5px 的邊框以 1 物理像素寬渲染。但是在 Android 中,新版系統(tǒng)中的內(nèi)置瀏覽器引擎會(huì)將邊框以 1px 寬進(jìn)行渲染喂饥,而在老版系統(tǒng)中消约,壓根就不會(huì)渲染。
而 box-shadow 的兼容性情況正好相反:Android 中可以正確處理 0.5px 的內(nèi)擴(kuò)散员帮,Safari 卻不會(huì)顯示或粮。
所以如果想要確保 iOS 和 Android 都能正常實(shí)現(xiàn),就需要結(jié)合 JS 做一些特性檢測(cè)捞高。
背景漸變
相應(yīng)的氯材,背景漸變方案的兼容性要好的多,性能也很不錯(cuò)硝岗,結(jié)合 SCSS 用著也很方便:
.hairline {
background: top center/100% 1px no-repeat linear-gradient(180deg, #000, #000 50%, transparent 50%),
bottom center/100% 1px no-repeat linear-gradient(0deg, #000, #000 50%, transparent 50%),
center left/1px 100% no-repeat linear-gradient(90deg, #000, #000 50%, transparent 50%),
center right/1px 100% no-repeat linear-gradient(270deg, #000, #000 50%, transparent 50%);
}
不過它不支持圓角氢哮,使用場(chǎng)景比較有限就是了。
縮小偽元素
而至于縮小偽元素的方式型檀,實(shí)現(xiàn)起來倒也不麻煩:
.hairline {
position: relative;
}
.hairline:after {
content: "";
position: absolute;
left: 0;
top: 0;
width: 200%;
height: 200%;
transform: scale(0.5);
transform-origin: top left;
border: 1px solid #000;
border-radius: inherit;
pointer-events: none;
}
不過通常并不推薦使用冗尤,一來它會(huì)占用至少一個(gè)寶貴的偽元素,二來像 input胀溺、select 和 img 這種不支持偽元素的還需要再在外面包一層其它元素生闲,有時(shí)不太優(yōu)雅。
其它實(shí)現(xiàn)方式
我在目前工作中一般只用到過以上三種方式月幌,其它方式比如 border-image 等倒沒怎么實(shí)際用過碍讯。不過看大漠講的 PostCSS Write SVG 的方案可行性貌似還比較不錯(cuò),之后有時(shí)間的話可以試試扯躺。
最后
在當(dāng)前捉兴,所有實(shí)現(xiàn)一物理像素邊框的方案或多或少都會(huì)有些問題,所以也沒有什么一勞永逸的方案录语,我們只能是在實(shí)際場(chǎng)景中去挑選合適的方案去使用倍啥。
之后還是希望各瀏覽器能盡快全都兼容 0.5px 的 border 或 box-shadow。而物理像素單位的話澎埠,一來加入規(guī)范的可能性不大虽缕,二來在未來出現(xiàn)更高像素比的屏幕時(shí)其可用性如何還不好說,所以希望不大蒲稳。