viewport 的理解

首先

屏幕是由一个一个显示单元组成的.
1 每一个显示单元都是物理世界真实存在的;
2 把一个显示单元的大小称为一个’物理像素’;
3 通常我们所说的 ‘分辨率’, 就是指一块屏幕显示单元的个数, 比如 750 叉 1334, 表示这块屏幕由 750叉1334 个显示单元组成

其次

通常情况下, 1 个显示单元对应 计算机系统中的 1px.
也就是说, 如果你设置了一个元素的 height:100px; 在屏幕中会有 100个显示单元来渲染它.
后来出现了一种情况
在相同大小的屏幕下,
屏幕分辨率不一样, 一个分辨率是 A, 而另外一个分辨率是 2A — 因为我们可以把显示单元做的更小了

这种情况的出现, 有如下的影响

  • 如果我们维持着: 计算机系统中的 1px, 对应物理上的 1个显示单元.
    那么同样一个页面, 在 A 显示正常, 在 2A 的情景下面, 就只会显示一半.

这种情况肯定是不可以的.所以我们需要针对这种情况做处理: 浏览器提供了一个 devicePixelRatio(设备像素比) 的属性, 用来标记:

标准显示单元的大小/当前设备的显示单元的大小

并且明确两条规则:

  • 1px 始终对应 1个显示单元

  • 标准的 1个显示单元大小为 x, 其他的显示单元, 可能是 1/2x, 1/3x

我们可以通过判断这个值, 来调整我们使用的 px 的大小,
比如:

devicePixelRatio = 1 的设备中, 元素a 的宽度为 100px;
devicePixelRatio = 2 的设备中, 元素a 的宽度为 200px;

ok, 那么我们来搞.
根据不同的 devicePixelRatio 来调整元素的样式.

    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)
    原文作者:云水摇啊摇
    原文地址: https://segmentfault.com/a/1190000009861458
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞