屏幕是由一個一個顯示單元組成的.
1 每個顯示單元都是物理世界真實存在的;
2 把一個顯示單元的大小稱爲一個'物理像素';
3 一般咱們所說的 '分辨率', 就是指一塊屏幕顯示單元的個數, 好比 750 叉 1334, 表示這塊屏幕由 750叉1334 個顯示單元組成javascript
一般狀況下, 1 個顯示單元對應 計算機系統中的 1px.
也就是說, 若是你設置了一個元素的 height:100px; 在屏幕中會有 100個顯示單元來渲染它.
後來出現了一種狀況
在相同大小的屏幕下,
屏幕分辨率不同, 一個分辨率是 A, 而另一個分辨率是 2A --- 由於咱們能夠把顯示單元作的更小了html
這種狀況的出現, 有以下的影響java
若是咱們維持着: 計算機系統中的 1px, 對應物理上的 1個顯示單元.
那麼一樣一個頁面, 在 A 顯示正常, 在 2A 的情景下面, 就只會顯示一半.瀏覽器
這種狀況確定是不能夠的.因此咱們須要針對這種狀況作處理: 瀏覽器提供了一個 devicePixelRatio(設備像素比) 的屬性, 用來標記:ide
標準顯示單元的大小/當前設備的顯示單元的大小
而且明確兩條規則:佈局
1px 始終對應 1個顯示單元idea
標準的 1個顯示單元大小爲 x, 其餘的顯示單元, 多是 1/2x, 1/3xcode
咱們能夠經過判斷這個值, 來調整咱們使用的 px 的大小,
好比:htm
devicePixelRatio = 1 的設備中, 元素a 的寬度爲 100px; devicePixelRatio = 2 的設備中, 元素a 的寬度爲 200px;
ok, 那麼咱們來搞.
根據不一樣的 devicePixelRatio 來調整元素的樣式.ip
var box = document.querySelector('.box'); var height = parseInt(getComputedStyle(box).height); var width = parseInt(getComputedStyle(box).width); box.style.height = height * parseInt(window.devicePixelRatio) + 'px'; box.style.width = width * parseInt(window.devicePixelRatio) + 'px';
這僅僅是一個元素的兩個屬性, 1000個元素, 每一個元素 5 個屬性, 就可讓你哭掉了.
因此這種處理方式確定是不能夠的.
而後咱們發現了 rem 單位.
它的簡單解釋:
當你給某個元素A 設置了 height:2rem 的時候 它會找到根節點(html) 的 font-size 值, 好比是 16px 而後拿 16 * 2 = 32px 做爲元素A 的最終 height.
這個就能夠利用了
讓元素使用 rem 做單位
而後控制根元素的 font-size 值, 在不一樣的 devicePixelRatio 下面的時候, 呈現不一樣的值
好比: devicePixelRatio = 1, font-size(root) = 100px; devicePixelRatio = 2, font-size(root) = 200px;
元素在這個時候, 就會自動響應大小的變化.
好, 開始搞:
var fontSize = 100 * parseInt(window.devicePixelRatio) + 'px'; document.documentElement.style.fontSize = fontSize;
嗯, 結果仍是不錯的, 在不一樣的分辨率下面, 咱們也能實現頁面相同了.
而後你會老是以爲, pc 上面的 100px, 和你 devicePixelRatio=2 的時候的 200px
的大小不一致的, 按道理來講應該是一致的.
的確不一致.
先明確一個概念
瀏覽器可視區域(visual viewport)
咱們以前說了 '計算機系統中的 1px 始終對應 1個物理顯示單元'
那麼對應 750*1334 分辨率的屏幕, 咱們一樣能夠這麼描述它:
屏幕的大小爲 750px*1334px.
前面已經說過了, 相同物理尺寸的屏幕, 分辨率可能不一樣, 由於顯示單元的個數不一樣.
因此這裏的 750px, 可能僅僅是標準下面的 375px;
另一個概念:ideal viewport
它表示的是說:
當前設備, 使用標準顯示單元爲單位的時候的大小.
好比說 750*x 的分辨率, devicePixelRatio = 2,
那麼它在標準顯示單元下面, 寬度就是 375px * x/2
最後咱們提一下 layout viewport, 這是爲何大小不一致的緣由:
歷史:
從 iPhone 發佈前夕提及, 開發人員發現, 本來爲 pc 開發的網頁 在 iPhone 上面顯示不全, 這部分能夠經過滾動條來解決. 可是使用 百分比佈局的頁面就坑爹了, 本來在 pc 端瀏覽器上擁有 的 20% 在 iPhone 上面就一點點了, 佈局徹底亂了, 坑啊. 爲了解決這個問題, 開發人員提出了一個的新的概念: 'layout viewport'
layout viewport的默認大小爲 980px, 而且默認縮放到和 visual viewport 區域通常大小.
在這種狀況下, 咱們能夠計算出layout viewport下,
一個 100px 寬度的元素, 對應的 visual viewport 下面的寬度 x
layout viewport / visual viewport = ele-width(layout viewport) / x
也就是
x = ele-width(layout viewport) * (layout viewport / visual viewport);
ideal viewport 下面的寬度, 只要再除以 devicePixelRatio 便可.
很明顯的看出來:
width(layout viewport) = width(visual viewport) 的時候, 兩個 viewport 中的元素寬度值
是相等的.
width(visual viewport) / devicePixelRatio = ideal viewport 中的元素的大小.
而咱們的最終追求, 就是
當你寫下 100px 的時候, 在任何 devicePixelRatio 下面的大小都是一致的.
要作到這一點, 就要作到它們的 ideal viewport 下面的大小始終一致的.
而一個元素在 ideal viewport 下的大小的計算公式爲:
( ele-width(layout viewport) * (layout viewport / visual viewport) ) / devicePixelRatio;
由於不一樣的設備的 visual viewport 的值是不一樣的, 咱們能夠控制讓 layout viewport 的大小始終
等於 visual viewport, 這樣比例始終爲 1
devicePixelRatio 在不一樣的設備中有不一樣
假設 ele-width(ideal viewport) = x; devicePixelRatio = n; 那麼 ele-width(layout viewport) = nx;
因此咱們只要保證, ele-width 的寬度, 始終爲 nx 便可, 由於一般狀況下咱們是知道 x 的.
how?
控制 layout viewport 的大小始終等於 visual viewport
經過 meta name="viewport" 的 content 的 initial-scale 來控制.
initial-scale = 1 , layout viewport 的寬度爲 375 (同ideal viewport) initial-scale = 2 , layout viewport 的寬度爲 188 initial-scale = 0.5, layout viewport 的寬度爲 750;
因此獲得的結論:
當 initial-scale 的值爲 1/devicePixelRatio 的時候, width(layout viewport) = width(visual viewport)
2 經過 rem, 以及根據不一樣的 devicePixelRatio 設置 根節點的 font-size 值, 來控制 nx 的值的大小.
而後須要給出一份基準值:
在 750(visual viewport), devicePixelRatio = 2 的時候, root(font-size) = 200px;
若是都作到這裏了, 那麼至少能夠達到:
在不一樣的 devicePixelRatio 下面元素的大小都是一致的.
可是依舊存在一個問題, 當前頁面是基於 750 (visual viewport) 定義的, 也就是說
當你的設備實際上只有 640(visual viewport) 的時候,
你的整個頁面仍是 750px, 就會出現滾動條.
因此咱們想要等比縮放一下.
如何操做?
直接等比縮放一下 root(font-size) 的值:
750/200 = 640/x x = 640 / (750 / 200)