思考一下
什麼是物理畫素?什麼是css畫素?
在 《掌握web開發基礎系列--長度單位》 這篇文章中已經介紹過了css畫素單位--px,這篇文章詳細探討一下裝置物理畫素和css畫素之間的關係。
“畫素”,是一個名詞,在不同的上下文中所描述的東西可能不一樣,但是也可能存在一定關係。
兩種畫素
注:下面很多是直接引用參考文章中的描述,主要原因是原文寫的很棒,為作者點贊!
物理畫素
裝置螢幕實際擁有的畫素點,螢幕的基本單元,是有實體的。比如iPhone 6的螢幕在寬度方向有750個畫素點,高度方向有1334個畫素點,所有iPhone 6 總共有750*1334個畫素點。
螢幕普遍採用RGB色域(紅、綠、藍三個子畫素構成),而印刷行業普遍使用CMYK色域(青、品紅、黃和黑)。
邏輯畫素
也叫“裝置獨立畫素”(Device Independent Pixel,DIP),可以理解為反映在CSS/JS程式裡面的畫素點,也就是說css畫素是邏輯畫素的一種。
除了css畫素是邏輯畫素還有其他常見的邏輯畫素嗎?
我們平時描述一張圖片寬高時一般用 200px * 100px
,這裡的px
也是邏輯畫素。
裝置畫素比(Device Pixel Ratio,DPR)
一個裝置的物理畫素與邏輯畫素之比。
畫素為什麼會有“物理”和“邏輯”之分,它們之間什麼區別?
其實在很久以前,的確是沒區別的,CSS裡寫個1px
,螢幕就給你渲染成1個實際的畫素點,DPR=1,多麼簡單自然~
後來蘋果公司為其產品mac、iPhone以及iPad的螢幕配置了Retina高清屏,也就是說這種螢幕擁有的物理畫素點數比非高清屏多4倍甚至更多。如果還按照DPR=1進行展示,那麼同一張圖片在高清屏上面顯示的區域面積會是非高清屏的1/4,這樣的話由於圖片在螢幕上的展示面積大大縮小,也會導致出現“看不清”的問題。
蘋果公司既然推出了Retina技術,那麼這種技術帶來了高清展示福利的前提下也要解決“DPR=1”的問題。怎麼解決呢?DPR!=1。蘋果公司經過一系列技術使用4個乃至更多物理畫素來渲染1個邏輯畫素,這樣一來,同樣的CSS程式碼設定的尺寸,在Retina和非Retina螢幕上看起來大小是一樣的,但在Retina螢幕上要精細得多。更多內容請閱讀《Retina (一種新型高解析度的顯示標準)》
在Retian屏上,DPR不再是1,而是大於1,比如2(iPhone 5 6 7 8)或3(iPhone 6 Plus等一系列Plus)或者為非整數(一些Android機),說不定還會漲。舉個例子,iPhone 6的物理畫素上面已經說了,是750 * 1334,那它的邏輯畫素呢?我們只需在iPhone 6的Safari裡列印一下screen.width
和screen.height
就知道了,結果是 375 * 667,這就是它的邏輯畫素,據此很容易計算出DRP為2。當然,我們還可以直接通過window.devicePixelRatio
這個值來獲取DRP,列印結果是2,符合我們的預期。
奇葩的iPhone 6 Plus
這裡不得不提一下iPhone 6 Plus(以及同尺寸的其他果機),它的實際物理畫素點個數是1080 * 1920,但如果你截個屏,你會發現截圖圖片的寬高是1242 * 2208;瀏覽器的screen物件會告訴你,6 Plus的邏輯畫素是414 * 736,正好是截圖寬度的三分之一,window.devicePixelRatio
值也為3。
所以現在我們有了3種不同的畫素值?什麼情況?
是這樣的,iPhone 6 Plus系統定義的螢幕畫素就是1242 * 2208,系統會自動把這些畫素點塞進1080 * 1920個實際畫素點來渲染,這個過程對於開發者是透明的,無需理會。
所以對於前端來說,可以直接把1242視為6 Plus的“物理畫素”,包括UI小姐姐們出圖也是以1242為標準的,因此不妨把1242 * 2208稱為6 Plus的“設計畫素”。
蘋果這是要鬧那樣?
其實,當初蘋果公司在確定6 Plus的DRP時,糾結了半天:選2吧,同樣的字號在6 Plus上看起來比6更小,不好;選3吧,字又顯得太大了,導致一屏能展示的內容還沒有6多;最適合視覺的DRP值是2.46,但這樣一個數字能把設計師和程式設計師們逼瘋。最後就想出了引入“設計畫素”這樣一個兩全其美的方案,既讓開發者開心,又讓使用者爽,豈不美哉?
1px邊框問題
在蘋果的帶動下,Retina技術在移動裝置上已經成了標配,所以前端攻城獅必須直面如下事實:
1. 你想畫個1px的下邊框,但螢幕硬是塞給你一條寬度為2—3個物理畫素的線。
2. 你沒法像安卓或iOS的同事那樣直接操縱物理畫素點。
複製程式碼
這就是初級前端面試必考題之“1px邊框問題”的由來。
1px邊框問題的解法千奇百怪,各顯神通,但以我的實踐經驗,最推崇的方法還是利用CSS3的transform: scale
,因為簡單直接、適用性和相容性好。
你不是給我兩個物理畫素點嗎?加個transform: scale(0.5)
,只剩一個點了~
三個物理畫素點?那就scale(0.33)
!
使用CSS的-webkit-min-device-pixel-ratio
媒體查詢可以針對不同的DPR做出處理 ,下面以Less程式碼為例:
@media (-webkit-min-device-pixel-ratio:2),(min-device-pixel-ratio:2){
.border-bt-1px(@color) {
position: relative;
&::after {
position: absolute;
bottom: 0;
width: 100%;
height: 1px;
background-color: @color;
transform: scaleY(0.5);
}
}
}
複製程式碼
上面介紹的是隻有一邊的情景,如果是四面都要有框,咋辦?
那就畫個DPR倍大小的矩形框,再scale
一下,完事~
再次感謝原文作者!