🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
## 究竟以哪个为设备独立像素 ### window.innerwidth、window.screen.width 的区别 开始时(`viewport scale=1`),二者的值是相同的,但是 `scale=2` 页面放大时,也就是设备独立像素缩小时,`window.innerwidth` 缩小了(按scale倍数缩小,除以scale),而`window.screen.width`不变(也可以说window.screen.width为初始默认的设备独立像素)。 当不在移动环境中时,`window.screen.width`始终为显示器屏幕的宽,`window.innerwidth`为浏览器可见区域的宽,包含滚动条(`$(window).width()`不包含滚动条)。 * * * * * ### 设备的独立像素的表示 window.innerWidth:浏览器可见区域宽度(包含滚动条,不过在移动端滚动条不单独占宽度,不占空间的,不滚动时还是完全透明的),这个值其实就可以表示设备独立像素的值了,甚至可以把它解读为设备独立像素。 **viewport scale大于1时,页面放大,window.innerWidth缩小,设备的独立像素减少,即点数量减少,为原来的1/scale。** **viewport scale小于1时,页面缩小,window.innerWidth放大,设备的独立像素增多,即点数量增多,为原来的1/scale。** * * * * * ### 分析 淘宝:html.clientWidth ```javascript var html = document.documentElement var rem = html.clientWidth / 10 html.style.fontSize = rem + 'px' ``` 小米:html.getBoundingClientRect().width ```javascript var html = document.documentElement var e = html.getBoundingClientRect().width document.documentElement.style.fontSize = e / 7.2 + "px" ``` 他们的实验区别: 1. window.innerWidth: 628 2. html.clientWidth:617 3. html.getBoundingClientRect().width:616.6666870117188 以上是在PC模式下的值,可以看到: 1是包含滚动条的。 2不包含滚动条,但是不够精确,明显是四舍五入取整的值,对精确计算不友好。 3不包含滚动条,最精确,能精确到小数位后13位。 > 在移动端,缩放时,他们都会变化,是相同的,但偶尔window.innerWidth的值会比后两者大1px(鼠标移到html元素上显示的值与后两者相同)。 回想之前我们视口缩放viewport scale: ```javascript // 注意这里,设置视口缩放时没有设置 width=device-width metaEl.setAttribute('content', 'initial-scale=' + scale + ',maximum-scale=' + scale + ',minimum-scale=' + scale + ',user-scalable=no,viewport-fit=cover'); ``` 之前`window.innerwidth`和`window.screen.width`对比时,我们已经知道了,页面放大时,设备独立像素缩小,`window.innerwidth` 缩小了,而`window.screen.width`不变,`window.screen.width`只会随着窗口大小而改变。 **`window.innerWidth`、`html.clientWidth`、`html.getBoundingClientRect().width`,三者没有区别,表现的特性相同,它们的值与将鼠标移到html元素上显示的值相同,都能代表随着视口缩放而变化的设备独立像素。** >[danger] 看来移动端开发很多东西还是要真机测试才行啊,上面的测试是在PC浏览器上模拟的,真机测试不是这样:只要scale不为1,后两者竟然都是980,看来还是得用window.innerWidth才靠谱啊。 上面是没有设置`width=device-width`时的效果。 试想一下,如果又设置缩放,又设置最佳视口宽度等于设备宽度会不会相互矛盾呢? 我们同时设置试一下: ```javascript // 注意这里,设置视口缩放时同时也设置了 width=device-width metaEl.setAttribute('content', 'width=device-width,initial-scale=' + scale + ',maximum-scale=' + scale + ',minimum-scale=' + scale + ',user-scalable=no,viewport-fit=cover'); ``` 首先我们发现,视口缩放不会触发`resize`事件了,之前是可以触发的。 当`scale>1`时`html.clientWidth`、`html.getBoundingClientRect().width`的值始终与将鼠标移到html元素上显示的值相同(始终为初始默认的设备独立像素值),不会跟随视口缩放而改变,只有当`scale<1`时才正常,也就是说,它俩最小不会小于初始默认的设备独立像素值(即最小不会小于window.screen.width的值)。 只有`window.innerWidth`能一直正常体现视口缩放时设备独立像素随着变化了。 那么此时,我们在想,到底使用哪个算基准值呢? 基准值 = ? / Z (Y = P / Z) 显然使用后两个的话,缩放时基准值也会保持不变,就会出现不正常,rem元素也会被缩放。 总结:不同时设置时,他们基本没有什么区别,无论用哪个做为基准值计算都是一样的,没有区别。同时设置时,问题就出来了,**同时设置是错误的做法,不要同时设置**,并且width默认就是device-width,所以其实可以不用设置这一项。 (不合理就不合理,不然视口缩放不会触发`resize`事件就不好了) * * * * * 如果只进行比较简单的适配,视口这样设置就可以了: ```html <meta name="viewport" content="width=device-width,user-scalable=no,initial-scale=1.0,viewport-fit=cover"> ``` 如果有用到视口缩放,就一定不要使用`width=device-width`。 * * * * * ### vh可以替代js实时计算的方案 我们是通过 `resize` 事件实时计算 基准值的,这种适配方案依赖于JS,如果不使用JS能实现类似的适配吗? 也可以,答案是用 vh 拼多多就是用的vh ```css html { font-size: 100vh / Z; } ``` 原理与JS版的同理。 ***** last update:2018-7-21 07:39:03