retina屏中1物理畫素border的實現

LevonLin發表於2017-11-20

問題的產生

retina屏會以2個(乃至3個)物理畫素來顯示一個CSS畫素(1px),所以在CSS中指定1px的邊框實際佔據的卻是2個以上物理畫素,在retina屏使用者體驗較差。

幾種解決方案(考慮1px=2dip)

使用0.5px

問題:只在Firefox and Safari 8+支援,安卓不支援。

使用圖片

採用一張圖片作為border:

retina屏中1物理畫素border的實現
border-width: 1px;
border-image: url(border.gif) 2 repeat;
複製程式碼

border-img屬性會將圖片(如上圖)切為九宮格,放到邊框的四邊和四角。由於圖片外沿一半為實色、一半為透明,所以1px的圖片邊框,實際顯示出的就是0.5px的邊框了。

問題:

  • 無法設定顏色
  • 邊框實際還是佔用了1px的空間
  • 不使用base64的情況下,要載入多一張圖片

使用漸變

原理類似上面的圖片,將1px的漸變拆為兩半,一半透明一半實色,但好處是作為背景不會實際佔據盒子的0.5px空間。

background: linear-gradient(180deg, black, black 50%, transparent 50%) top left / 100% 1px no-repeat,
            linear-gradient(90deg, black, black 50%, transparent 50%) top right / 1px 100% no-repeat, 
            linear-gradient(0, black, black 50%, transparent 50%) bottom right / 100% 1px no-repeat, 
            linear-gradient(-90deg, black, black 50%, transparent 50%) bottom left / 1px 100% no-repeat; 
複製程式碼

問題:無法處理圓角

使用縮放

給一個原元素兩倍大小的偽元素,指定1px邊框,再縮小一半,即可得到0.5px邊框。

.retina-border-scale {
    position: relative;
}
.retina-border-scale:before {
    content: '';
    border: 1px solid black;
    transform: scale(0.5);
    transform-origin: 0 0;
    width: 200%;
    height: 200%;
    position: absolute;
    left: 0;
    top: 0;
}
複製程式碼

問題:

  • 原元素需要用相對定位
  • <td>元素上不起作用

其他方法

  • 使用box-shadow:實現簡單,但效果不好、會有陰影
  • 直接按照放大的設計稿重構,再指定viewport的initial-scale=0.5縮小整個頁面:簡單粗暴

對非retina屏的相容

由於非retina屏下的1物理畫素border直接用px做單位即可,因此針對不同螢幕,會有多套樣式實現。
而為了正確地應用樣式,首先得有判斷retina屏的能力。這其中,CSS的媒體查詢裡提供了min-device-pixel-ratio或min-resolution;而瀏覽器也提供了window.devicePixelRatio這個js API來獲取CSS畫素和物理畫素的比值。
最後,我們就可以根據螢幕在程式碼裡應用適當的樣式了。

ref

CSS, Retina, and Physical Pixels


相關文章