一個畫素裡複雜紛擾的世界
文 | 啃先生 Mar.3rd.2016 首發於微信公眾號(啃先生)
上一篇發了《【移動適配】移動Web怎麼做螢幕適配》
壹 | Fisrt
在CSS的世界裡Px是原子操作,我們無法定義邊框的寬度是0.5px,最小都是1px。所以有以下結論:
然而,對於精益求精的產品而言,這種認識只是片面的!例如:我做了一個頁面,上面只有兩條邊框,在高清屏(如iPhone5s)上,經過特殊處理的邊框比1畫素的邊框還要細。
因此,在高清屏上,border-width:1px;並不是最小邊框。瀏覽器可以顯示的最小粒度比CSS中的1px還要小。
貳 | Second
那麼CSS中的1px是什麼?瀏覽器是怎麼渲染它的?
網頁在一個叫viewport的東西里渲染,可以理解為畫布,畫布被分成 N x M 個小方格,1個CSS畫素,就是其中的一個小方格。
viewport又是什麼?
網頁在viewport上渲染,可以想像在PS上畫東西時,上面也有個畫布,這個畫布分割了 N x M 個方格,N是它的寬度,M是它的高度。寬高都可以任意設定,所以說viewport是虛擬的。假設設定寬度是400,那麼瀏覽器顯示區域的橫向將被分為400份,CSS的1px佔的寬度就是顯示區域的 1/400。如果是980,那就是1/980。
viewport值不一樣時,對頁面元素寬度的影響
看一個的頁面,不動任何其他程式碼,只修改viewport的寬度,頁面發生了什麼變化
程式碼如下:
以下是支行結果
viewport=500的情況
viewport=900的情況
我們只分析使用者頭像的圖片,已知頭像寬度是50px。
-
當viewport寬度為500時,螢幕橫向被分為500份,每份1px,所以頭像寬度是螢幕的1/10。(500/50=10)
-
當viewport寬度為900時,螢幕橫向被分為900份,每份1px,所以頭像寬度是螢幕的1/8。 (900/50=18)
所以,在CSS中,1px是指viewport中的一個小方格,而viewport寬度是可以任意設定的。
叄 | Third
那麼,怎麼合理設定viewport的寬度?
viewport的寬度可以是數字和字串"device-width"。device-width指裝置寬度。
-
當取值為數字時,指不論是什麼手機螢幕,viewport都被分為那麼多份
-
當取值為device-width時,指的是手機螢幕的viewport寬度被設定為跟手機寬度一樣。那這個寬度怎麼算的呢?
device-width的演算法
先理清幾個非常關鍵的術語概念:
-
物理畫素:買手機的時候會有一個 n*m 的解析度,那是螢幕的n*m個呈像的點,一個點(小方格)為一個物理畫素。它是螢幕能顯示的最小粒度
-
CSS畫素:就是CSS裡的Px,上面已經講了是viewport中的一個小方格。
-
畫素密度:即dpi或ppi,螢幕每英寸所佔的物理畫素點。
而CSS畫素與物理畫素之間是有一個轉換關係的。即是:
其中,轉換系統計算過程如下:
安卓的密度區域和轉化係數的對應表
iPhone的密度區域和轉化係數的對應表
(宣告:以上三個圖片來源於 http://tgideas.qq.com/webplat/info/news_version3/804/7104/7106/m5723/201509/376281.shtml)
例如:某檯安卓手機,解析度是 1920*1080,螢幕物件線是5英寸。那麼在這臺手機上1個CSS畫素,佔了多少個物理畫素?
第一步:勾股定理算出對角線的解析度,即 √(1920²+1080²)≈2203px
第二步:算出dpi。對角線的解析度/對角線英寸 = 2203/5≈440dpi
第三步:得出轉換系數。根據上面的圖片,安卓手機440dpi,屬於XXHDPI,轉換系數是3
因此這臺手機中,1個CSS畫素 = 3*物理畫素。即1個CSS畫素佔了3個物理畫素。
這個轉換系數,也等同於dpr,裝置畫素比。
因為很明顯device-width的寬度值單位是CSS畫素。所以當viewport設定為device-width時,此時它是手機橫向解析度 / 轉換系數。即:
例如上述的例子中,該檯安卓手機的device-width是1080/3 = 360,即viewport的寬度是 360 CSS畫素。
而viewport設定為固定的數字有可能會破壞這種轉換關係,都是建議設定viewport寬度為device-width,這樣1個CSS畫素就盡最大可能剛好佔dpr個物理畫素點。
肆 | Fourth
為什麼會出現比border-width:1px更細的邊框?
螢幕能夠顯示的最小粒度是1個物理畫素,而當viewport寬度設定為device-width時,1個CSS畫素佔用的物理畫素是由轉換系數決定的。所以,像iPhone6這樣的高清屏上,轉換系數為3,border-width:1px,這個邊框佔了3個物理畫素。如果能讓某個border的寬度為1個物理畫素,那麼它就比1個CSS畫素要細,而本文最開始邊框那個更細是因為經過特殊處理後使其只佔用1個物理畫素。
讓1個CSS畫素佔用一個物理畫素的辦法。
-
方法一:viewport的scale
在viewport的屬性裡,除了設定寬高的width和height外,還有縮放比例scale。
當scale為1時,頁面大小正常,但scale為0.5時,頁面被縮小了1倍,本來1個CSS畫素寬度佔2個物理畫素寬度,縮小後的border-width:1px就只佔1個物理畫素。程式碼如下:
其中,initial-scale為1/dpr。
優點:
-
不用為border寫很多樣式程式碼,跟原來一樣border:1px solid #D5D5D6即可
-
可以輕鬆設定圓角 border-radius。
缺點:
1. 整個頁面縮小了,副作用就是字型,圖片,其他元素的尺寸邊距等等都同比例縮小了。這種情況,設定viewport為dpr*document.documentElment.clientWidth,再結合我上一篇文章《【移動適配】移動Web怎麼做螢幕適配(一)》,即可解決。
-
方法二:transform scale
方法一是縮放整個頁面,在CSS3標準裡,可以縮放某個元素。例如某個div.border-top,為它設定如下樣式,使該DIV的頂部有一個邊框
.border-top{position: relative;border-top: none !important;} .border-top:after { content: " "; position: absolute; left: 0; top: 0; width: 100%; height: 1px; background-color: #D5D5D6; -webkit-transform-origin: 0 0; -ms-transform-origin: 0 0; transform-origin: 0 0; -webkit-transform: scaleY(0.5); -ms-transform: scaleY(0.5); transform: scaleY(0.5); }
在該DIV後面新增一個高度為1px的內容,並且縮小dpr倍,這裡就是縮小成原來的1/2。
優點是整個頁面不用縮放,缺點是border程式碼較多,無法實現border-radius圓角
寫完瀕臨虛脫。。
- 深入理解viewport和px(http://tgideas.qq.com/webplat/info/news_version3/804/7104/7106/m5723/201509/376281.shtml)
- A tale of two viewports(http://www.quirksmode.org/mobile/viewports.html)
適配的問題還沒講完,但又臭又長的純技術文太硬了,下期可能會喝點湯,講講故事。
開始碼字才知道碼字不易,堅持碼字更不易。轉載請宣告來源
如果覺得文章有用,順手點選下方的推薦