viewport 的理解

首先

屏幕是由一個一個顯示單元組成的.
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 便可.

很明顯的看出來:

  1. width(layout viewport) = width(visual viewport) 的時候, 兩個 viewport 中的元素寬度值
    是相等的.

  2. width(visual viewport) / devicePixelRatio = ideal viewport 中的元素的大小.

而咱們的最終追求, 就是
當你寫下 100px 的時候, 在任何 devicePixelRatio 下面的大小都是一致的.
要作到這一點, 就要作到它們的 ideal viewport 下面的大小始終一致的.

而一個元素在 ideal viewport 下的大小的計算公式爲:

( ele-width(layout viewport) * (layout viewport / visual viewport) ) / devicePixelRatio;
  1. 由於不一樣的設備的 visual viewport 的值是不一樣的, 咱們能夠控制讓 layout viewport 的大小始終
    等於 visual viewport, 這樣比例始終爲 1

  2. devicePixelRatio 在不一樣的設備中有不一樣

    假設 ele-width(ideal viewport) = x;
    devicePixelRatio = n;
    那麼 ele-width(layout viewport) = nx;

因此咱們只要保證, ele-width 的寬度, 始終爲 nx 便可, 由於一般狀況下咱們是知道 x 的.

how?

  1. 控制 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)
相關文章
相關標籤/搜索