淺談移動Web開發(上):深刻概念

PPI

什麼是PPI

PPI的複雜之處在於若是他所屬的上下文環境不一樣,意義也會徹底不同。 當咱們在談論顯示設備的PPI時,它代指的屏幕的像素密度;當咱們在談論和圖片相關時,咱們談論的是打印時的分辨率或者打印機的打印精度。這裏咱們主要描述的前一種狀況.css

PPI全稱爲Pixel Per Inch,譯爲每英寸像素取值,更確切的說法應該是像素密度,也就是衡量單位物理面積內擁有像素值的狀況。html

 

如上圖所示,在1英寸單位內面積內擁有的像素越多,密度越大,PPI值就越高。但像素密度的實際意義是什麼?它表達的是什麼?或高或低對設備顯示來講有什麼影響?css3

通常來講,咱們固然但願PPI值越高越好,由於更高的PPI意味着在同一實際尺寸的物理屏幕上能容納更多的像素,可以展示更多的畫面細節,也就意味着更平滑的畫面。原理以下:web

什麼是Pixel

但你有沒有仔細相關Pixel Per Inch中的pixel像素的概念究竟指的是什麼樣的像素?你可能會反問我像素難道還分不少種不成?我能夠很肯定的告訴你,是的。算法

設備像素

不管是早期的CRT顯示器仍是現在的LCD顯示器,都是基於點陣的。也就是說經過一些列的小點排列成一個大的矩形,不一樣的小點經過顯示不一樣的顏色來顯示成圖像。好比下圖就是LCD顯示器上一個6x6個小點排列成的矩陣:express

注意每個像素(pixel,也能夠稱之爲dot)又是由三個子像素(subpixel)紅綠藍組合而成。當須要顯示圖片信息時,它的工做原理能夠以下圖所示:瀏覽器

上圖中的左側是放大以後咱們能看到的像素,而右側就是對應像素在顯示器上的顯示狀況了。app

注意上圖表明的僅是LCD顯示器的物理像素狀況,早期的CRT顯示器的物理像素一樣也是由獨立的點組成。可是不存在subpixel的概念,狀況以下圖所示:ide

上面描述的這些顯示器上的像素咱們就稱之爲物理像素(physical pixel)或者設備像素(device pixel)。函數

CSS像素

做爲Web開發者,咱們接觸的更多的是用於控制元素樣式的樣式單位像素。這裏的像素咱們稱之爲CSS像素。

CSS像素有什麼特別的地方?咱們能夠借用quirksmode中的這個例子:

假設咱們用PC瀏覽器打開一個頁面,瀏覽器此時的寬度爲800px,頁面上同時有一個400px寬的塊級元素容器。很明顯此時塊狀容器應該佔頁面的一半。

但若是咱們把頁面放大(經過「Ctrl鍵」加上「+號鍵」),放大爲200%,也就是原來的兩倍。此時塊狀容器則橫向佔滿了整個瀏覽器。

弔詭的是此時咱們既沒有調整瀏覽器窗口大小,也沒有改變塊狀元素的css寬度,可是它看上去卻變大了一倍——這是由於咱們把CSS像素放大爲了原來的兩倍。

CSS像素與屏幕像素1:1一樣大小時:

CSS像素(黑色邊框)開始被拉伸,此時1個CSS像素大於1個屏幕像素

也就是說默認狀況下一個CSS像素應該是等於一個物理像素的寬度的,可是瀏覽器的放大操做讓一個CSS像素等於了兩個設備像素寬度。在後面你會看到更復雜的狀況,在高PPI的設備上,CSS像素甚至在默認狀態下就至關於多個物理像素的尺寸。

經過上面這個例子我想傳遞一個很是重要的概念,就是CSS像素歷來都只是一個相對值。

正確答案

回到PPI上來,如今咱們有了兩種像素,設備像素和CSS像素。那麼PPI中的像素是指哪種?

請記住,PPI中的pixel指的應該是物理像素

可是在維基百科對PPI的解釋中,pixel被解釋爲一種相似於分辨率下的像素:

The apparent PPI of a monitor depends upon the screen resolution (that is, the number of pixels) and the size of the screen in use; a monitor in 800×600 mode has a lower PPI than does the same monitor in a 1024×768 or 1280×960 mode.

上面這段話是在說,同一尺寸的顯示器在800x600分辨與1024x768分辨率下的像素密度明顯是不一樣的,明顯後者單位面積內的像素更多,固然後者的像素密度更高。

這裏考慮了另外一種狀況,即在同一顯示器下由於分辨率調整致使顯示器的像素密度不一樣。這裏的像素雖然是否是在瀏覽器中顯示,但原理也相似於CSS像素,即由多個物理像素組成一個指定分辨率下的像素。

但問題是,這樣的比較是沒有任何意義的,咱們一般在比較PPI時,必定是在跨設備比較,爲了體現設備的技術優點,也必定是拿設備的最優或者極限狀況進行比較,這樣狀況下分辨率下像素是與物理像素一一匹配的。 不能說一臺23寸的2k顯示器和一臺23寸的1080p顯示器由於都能調整到1440x960的分辨率,那麼他們的PPI就相同了?PPI終究是體現設備某方面性能的參數。

也就是說,當咱們在談論一臺設備的PPI時,它是一個定值,是一個固定的參數。

那麼PPI怎麼計算呢?沒錯,就和你想的如出一轍,用屏幕邊的物理像素除以物理尺寸便可,以Samsung Galaxy S4爲例:

因而可知Galaxy S4的屏幕分辨率爲441PPI。

The Bad and the Ugly

但PPI太高一樣也會帶來問題,相同的圖片素材,在越高的設備上會顯示的越小。如下是一個像素在不一樣PPI設備上的可見狀況,隨着PPI的增高可視度愈來愈小:

那麼能夠預見一種很糟糕的狀況是,同一尺寸的屏幕下假設PPI提升了一倍,極可能程序界面縮小了4倍(由於在屏幕尺寸不變的狀況下物理像素點面積是原來的1/4)。

以Surface Pro 3爲例,它的默認分辨率是2160x1440,也就是說Surface這臺設備的屏幕物理像素有2160x1440個點,同時默認分辨率狀況下,一個點物理像素點對應於一個分辨率像素。 但由於屏幕只有12寸,像素密度很是高,因而就出現了上面的問題,各個文字和圖標被縮的過小了,電腦是徹底不可用的。

解決方法是,Windows默認將全部的文本和素材(實際上就是分辨率像素)都放大了1.5倍(在「屏幕分辨率」-「放大或縮小文本和其餘項」中進行了設置),原來是一個物理像素對應一個分辨率下的像素,如今則是1.5個物理像素對應一個分辨率下的像素,也就意味着分辨率下的像素變大了,實際分辨率下降了,已經變成了1440(2160/1.5)x900(1440/1.5)(此時若是你嘗試用window.screen.width/window.screen.height去檢測返回結果也會是1440x900)。這裏留給讀者一個問題,

這樣和直接將PC的分辨率調整爲1440x900有什麼區別呢?

但把素材和文字放大就真的一勞永逸了嗎?不,甚至還會帶來反作用。放大素材對位圖來講是很是危險的一件事。假設一款軟件中的素材圖片分辨率爲32x32,可是爲了配合總體界面的拉伸,它也必須被拉伸至原來的1.5倍等於爲48x48。你必定有在Photoshop中把圖片強制放大爲原來幾倍的效果的經驗。 這樣以來,圖片素材就變得模糊了。同時由於Window使用的字體爲點陣字體而非矢量字體,因此甚至在軟件中的字體也會變得模糊。

簡單一點來講,採用這種技術須要將32x32的圖片強制拉伸爲48x48,多出來的像素如何憑空生成?計算機只有猜想了,經過線性插值算法。因此圖片便會出現模

糊。

但位圖可能會被拉伸的問題並不是也是絕對的,假設軟件須要顯示的icon大小爲32x32,可是圖片素材大小爲64x64,那麼即便Windows的UI界面拉伸1.5倍,icon大小爲48x48,由於原圖片足夠大,圖片仍處於未拉伸的狀態。那麼也不會模糊。

反過來咱們能夠得出結論,爲了讓在低PPI上和高PPI上圖片顯示的效果一致,圖片素材應該儘量的高清。

Apple的Retina技術使用的也是上面相同的方案。以15.4寸的Retina版Macbook Pro爲例。顯示屏的物理像素點實際上有2880x1880,但其實默認的最優分辨率只有1440x900,恰好是物理像素的一半。也就是說操做系統默認使用了4:1的縮放。但這一樣也有可能會出現使用軟件虛化的問題。

我不清楚Mac軟件開發中是如何解決這個問題的,但能夠參考iPhone開發中的解決方案,蘋果鼓勵開發者準備兩份素材,普通和高清素材。而且經過素材文件名後綴來區分,好比普通素材名稱爲apple.png,那麼高清素材名稱就爲apple@2x.png。天然高清素材是普通素材面積的四倍,系統會優先使用高清素材,但自動縮小到普通素材的大小,這樣也就不存在圖片拉伸的問題了。

PPI之於Web

從上面咱們得知,由於高像素密度設備下的UI會採用必定比例的縮放,因此CSS像素也會面臨一樣的問題:

正如上圖所示,左側普通屏幕中,2x2的CSS像素真的只須要2x2的物理像素。可是右側高清屏中,2x2的CSS像素卻須要4x4的物理像素。

我剛剛有說道解決高清PPI下圖片渲染問題的方法之一就是使用更高清的圖片素材。但問題是須要有多高清?

在Retina顯示屏上,根據上一節描述的原理,當咱們須要渲染一張32x32的圖片,咱們實際上須要準備64x64的素材。由於蘋果默認把全部素材都進行了兩倍的放大。但若是有一臺更高清的設備,進行了三倍或者四倍或者更高的倍數,咱們豈不是須要準備更多尺寸或者體積更大的文件素材?在Web開發中咱們正在面臨這樣的問題。

首先咱們要學會如何表達和判斷這樣一種CSS像素和物理像素不平等。

DevicePixelRatio

DevicePixelRatio定義以下:

window.devicePixelRatio = physical pixels / dips

分母dips全稱爲device-independent pixels,譯爲與設備無關像素。 更通俗的說應爲與物理像素無關的CSS像素。

以iPhone4爲例,在垂直狀態下手機的物理像素寬度有640px,可是由於2:1縮放的關係,此時的dip,設備報告給咱們的寬度只是320px。 此時的DevicePixelRatio就爲 640 / 320 = 2;

devicePixelRatio說白了就是手機的物理像素與實際使用像素的縮放比。

注意devicePixelRatio並不是是一個默認值。在默認狀況下CSS像素是由手機默認的縮放決定的。但同時由於瀏覽器頁面也能夠被人爲的進行縮放。好比iPhon4中默認的分辨率寬度爲320px。瀏覽網頁時咱們徹底能夠自行放大兩倍爲160px。這樣以來window.devicePixelRatio就變味了 640 / 160 = 4。

dppx

與divicePixelRatio幾乎等價的一個概念時dppx:dots per pixel。 表示單個CSS像素佔用的物理像素個數。仔細想一想,這與devicePixelRatio實際上是一個意思, iPhone4的dppx爲2,不就是與devicePixelRatio恰好相等嗎。devicePixelRatio是從宏觀上來講這件事。把總體寬度作運算。dppx是從微觀角度上說這件事,考慮的是單個像素之間的比較。

dpi

請記住,當咱們在談論一臺顯示設備的像素密度時,dpi與ppi是等價的。dots per pixel中的dots就是代指物理像素。

可是若是你在mediaquery中使用dpi是就要注意了,Chrome會在控制檯中提示你使用dppx而非dpi:

Consider using ‘dppx’ units instead of ‘dpi’, as in CSS ‘dpi’ means dots-per-CSS-inch, not dots-per-physical-inch, so does not correspond to the actual ‘dpi’ of a screen. In media query expression: only screen and (-webkit-min-device-pixel-ratio: 2), not all, not all, only screen and (min-resolution: 192dpi), only screen and (min-resolution: 2dppx)

上面這段話的意思是,在mediaquery中inch表示的CSS定義中的一英寸,而非生活中物理定義的一英寸。

實話實說我並無找到關於CSS中一英寸的定義,可是在W3C關於Resolution的定義中,咱們能夠看到看到它所定義的1dppx是與96dpi具備一樣含義的。那麼2dppx也就是192dpi了咯。這固然脫離了咱們傳統上的dpi了,Surface Pro 3的dpi(也就是ppi)可以達到216ppi,可是在默認未放大界面時的dppx仍然能夠是1。

CSS Reference Pixel

我的人爲這是一個很雞肋的概念,但也正是由於瞭解的人太少了,仍是須要值得一提。

假設咱們規定了CSS像素值須要與設備像素大小相等,但當隨着手持設備距離人的遠近不一樣,設備像素密度的不一樣,都會致使咱們看見的設備上的CSS像素的可見大小發生變化(相似於巨大的月亮由於離地球遙遠在人眼看來也不過像硬幣同樣大小)。爲了保證CSS像素在不一樣設備和不一樣距離上觀測到的大小保持一致保持連貫性。W3C定義了一個CSS相對像素(CSS reference pixel)的概念

It is recommended that the reference pixel be the visual angle of one pixel on a device with a pixel density of 96dpi and a distance from the reader of an arm’s length. For a nominal arm’s length of 28 inches, the visual angle is therefore about 0.0213 degrees.

W3C規定,把人眼可以辨別到的,距離本身一個手臂長度(約28英寸),像素密度爲96dpi設備上的一個物理像素設爲參考像素。因此咱們能夠算出眼睛看到參考像素的視野角度爲0.0213度:

有了這一系列參照,經過三角函數關係,咱們能夠算出一樣一臺設備在不一樣距離下CSS像素理想的大小。 當遠離觀察者時像素應該增大,當靠近觀察者時像素應該減少:

這麼作的優點在於不管設備距離觀察者距離是多少,也不管設備的像素密度和物理像素大小是多少,觀察者看到的CSS像素是一致的,保證了用戶體驗的一致性:

但問題是如何來實踐這一標準呢?

<meta name="viewport">

咱們有了物理像素,CSS像素——那麼問題來了,當你再手機上使用瀏覽器打開網頁時,網頁應該按照哪種寬度進行渲染?

首先咱們須要瞭解一個概念:viewport,我常見到的中文譯爲視口,但我的以爲這個翻譯有一些晦澀。 Viewport是用於限制Html元素——「限制」這兩個字不是那麼好理解。quirksmode上有一篇文章談到這個概念時打了一個很是形象的比方:

假設body標籤內有一個塊狀元素寬度爲10%: div {width:10%;},咱們知道當咱們縮放瀏覽器時這個塊狀元素的寬度也會跟着變化。 這是由於它的寬度佔它父元素的10%。那麼它的父元素,也就是body元素的寬度是由誰決定的呢?

咱們知道一個塊狀元素默認寬度爲它父元素的100%,也就是body元素的寬度與包裹它的html元素寬度相同。那麼問題又變成了html元素的寬度是由誰決定的?

答案是瀏覽器窗口。如今咱們能夠概括起來,html元素是被瀏覽器限制而且包裹起來的。html的寬度就是瀏覽器的寬度。

但事實上,html元素寬度是佔據viewport的100%,而在桌面瀏覽器中,viewport與瀏覽器窗口大小恰好相等(注意,這僅僅是在桌面瀏覽器上)。

OK,在因而咱們獲得了一個結論,html寬度是由viewport決定的,可是 在桌面瀏覽器中,viewport大小與瀏覽器窗口大小相等。

但這一套規則在手機則是沒法被執行的。大部分手機的屏幕分辨率目測只有400px,若是頁面上真的有某一個頁面元素僅佔10%,也就是40px的話,肉眼幾乎是沒法分辨的。實際狀況應該會更糟糕,iPhone4的Safari默認是以980px來渲染網頁的。若是你在Chrome以桌面版的方式訪問stackoverflow,那麼結果會是這樣的:

體驗很是糟糕吧,全部的連接幾乎都沒法準確點擊。那麼如何解決這個問題?

第一個辦法,放大頁面。

咱們會很習慣的用手勢去放大頁面。可是要注意咱們這裏作的僅僅是放大頁面,改變的是頁面的縮放(scale),效果與PC上瀏覽器的相似。可是沒有改變頁面的佈局,此時用於渲染頁面佈局的layout仍然是980px

第二個辦法是,改變佈局。
好比下面一個頁面上有一張320px寬的圖片,若是咱們以默認的980px去渲染的話,它會顯得過於窄小:

但若是咱們能夠將渲染它的佈局設爲320px的話,看上去就會好不少了,同時此時咱們也未對頁面

進行縮放:

固然你也能夠結合上一步,同時對頁面進行縮放:

不只僅是放大,即便是在320px的像素下,咱們也能夠進行縮小:

迴歸到技術上,以上這些均可以經過viewport標籤來解決,好比說上面的需求,把佈局設定爲320px,同時進行1.5倍的縮放:

<meta name="viewport" content="width=320, initial-scale=1.5">
所見即所得,須要設置的屬性在content以逗號分割開來,表示頁面佈局寬度,表明頁面初始狀態的縮放比例,若是你不想讓用戶進行縮放,還能夠添加字段來保證用戶沒法進行縮放。widthinitial-scaleuser-scalable=no

更重要的是,咱們還能夠無需指定特定寬度,經過設置width=device-width,指定佈局寬度等於手機分辨率寬度(可是咱們不用關心手機分辨寬度是什麼)來更好的利用響應式設計。注意這裏的device-width表示手機的分辨率寬度,而並不是手機物理像素寬度。iPhone4在垂直狀態下物理像素寬度爲640,這裏的device-width表明的則應該是它的dip像素320px。

給viewport標籤添加width=device-width適用於這樣一種狀況:你在爲移動設備開發的響應式網頁時,你會面臨多重分辨率狀況,可是你又沒有必要使用到重量級的mediaquery,同時也爲了不手機瀏覽器使用桌面分辨率寬度去渲染頁面, 同時這還能兼容在手機橫握或者豎握的狀況。 這樣讓你的響應式頁面可以適用大多數的移動設備。

寫到這裏咱們能夠作一個總結,viewport標籤的做用是什麼?它可以讓你撇開設備的干擾,告訴設備你想用什麼樣的寬度渲染網頁。讓它聽命於你,而不是你聽命於他。

上面咱們談到viewport有個半專業的名詞成爲layout viewport,雖然它是一個非官方的詞彙,可是很是多的文章都引用了這個概念。layout viewport專用於頁面渲染的控制。還有一種viewport稱之爲visual viewport,能夠譯爲可視窗口。兩種viewport的區分以下:

由此能夠看出visual viewport就比如是瀏覽網頁的一個窗口,網頁正是這窗外的景色。固然咱們還會碰見layout viewport與visual viewport大小相等的狀況。好比像下面這樣:

這也就是我上面描述的width=device-width了。

番外篇:PPI和DPI使用的更多場景

在文章的開頭我有說PPI在不一樣上下文中的含義是不一樣的,若是你仍有好奇心,能夠繼續往下閱讀。接下來咱們談談Web之外的PPI含義。

首先咱們要重申上面的結論,就談論顯示設備的像素密度而已,PPI和DPI和同樣的概念,而且其中的像素pixel和點dots代指的都是物理像素。

若是你去查看一張JPG圖片的屬性時,你會發現有橫向或者縱向的以dpi爲單位的屬性或者在Phototshop新建一份文檔時,要填寫一個以ppi爲單位的屬性值:

這裏也存在被混用和混淆的地方。其實他們都表示打印時的分辨率值。意爲在打印時每英寸上的像素(也就是跟接近PPI,但咱們更經常使用DPI)。這裏的英寸固然再也不是屏幕像素了,而是紙張尺寸了。

PPI或者DPI對於圖片來講意味着什麼?準確來講什麼都不意味着。 一張圖片只是存在相機或者硬盤裏的數據文件而已,你能告訴我它有多少英寸長或者多少英寸寬嗎?只有當它被打印出來的時候纔會涉及到打印媒介的尺寸,DPI纔有意義。 若是你想讓圖片更豐富,惟一的辦法是增長圖片的像素,提高你的拍攝技巧。

固然在紙張上是沒有像素的概念。但咱們能夠去抽象的去想象它。假設有一張300x300像素的圖片。打印分辨率的爲30DPI,那麼最後打印出來尺寸爲10x10英寸。假如打印時的DPI值爲300DPI,那麼打印出來的尺寸則爲1x1英寸。因此咱們能夠把DPI當作調節打印尺寸大小的手段。

那麼DPI值越高,圖片就越小就越清晰?固然也並不是如此。若是你距離60釐米去觀看一張194DPI打印出來的圖片。你會無法區分它究竟是194DPI仍是300DPI。由於人眼的分辨率是有限的。這對顯示設備一樣通用的。iPhon4的像素密度有326DPI,而New iPad的像素密度只有264DPI,New iPad的顯示效果會更差嗎?參考大多數人使用的距離和方式,其實眼睛獲得的效果實際上是無太大差別的。這也是爲何大型顯示器或者戶外廣告DPI都不會很高,由於咱們觀看他們的時候距離很遠,效果並不是太差。

最後咱們能夠來看另外一個場景的DPI:描述打印機的打印分辨率:

當一張顯示器上的圖片打印在圖片上的時候,像素這個概念實際上是咱們想象出來的,更加實際的概念時是印刷設備的每個「點」:

當你嘗試去用放大鏡去查看彩色印刷物品上的圖片時,從小到大你看到的結果應該是這樣的:

爲何會這樣?簡而言之,印刷的原理是經過半色調(halftone)技術,經過控制CMYK四種顏色點印刷時的每個印刷點的大小,角度,間隙來模擬出一種顏色的感受:

好比當你以600DPI打印一張150PPI的圖片時,每個像素應該包含16個點(600dots / 150pixels = 4)。

從上面咱們已經知道PPI可以決定印刷品物理尺寸的大小,打印機的DPI參數更是能進一步決定印刷體的好壞。咱們用於都在追求更高的DPI和PPI。

150dpi一般已是被認爲算的上是高質量的打印分辨率了。新聞報紙使用的分辨率一般是85dpi。戶外的廣告牌一般使用的是45dpi。可是由於距離的關係你不會以爲他們的印刷質量太差。

結尾

這篇文章我把移動開發中可能會涉及到的概念都作了一些涉及。在下篇中我將運用到這些概念,而且總結在移動設備上的圖片加載方案。

參考文獻(已在文中引用的就不在此列舉了):

相關文章
相關標籤/搜索