头图: @Linksphotograph

前言

在面向各种设备的 Web 开发中,往往需要得到用户当前屏幕的各种状态,已得到最佳的渲染效果,那么这里就有几个常用但是往往没遇到会被忽略的问题:

  • 如何获得用户物理分辨率?
  • 如果检测用户是否缩放了页面?
  • 如何检测用户是否覆盖了页面字体的大小?

说实话,这几个问题看起来简单,但是具体要答得完整,不容易,容易踩坑。

如何获得用户物理分辨率?

分辨率,很容易联想到 Window.screen 对象中的 heightwidth 属性,当我在一块 100% 缩放的 23 寸 1080P 显示器上执行

console.log(screen.width, '*', screen.height)

的确也返回了 1920 * 1080 的结果,让人误以为这就是正确答案了,但是注意到我上面提到的,这是一块 100% 缩放下的屏幕,我们再看看一块 200% 缩放的 2736 * 1824 分辨率的 13 寸屏幕。执行上面的代码,得到的结果却是 1368 * 912

有没有注意到, 1368 * 912 乘以 200% 不就是 2736 * 1824 吗,那这个缩放比例我们可以拿到吗?还真的可以,Window.devicePixelRatio 就是我们需要的东西,MDN 上的解释是

此属性返回当前显示设备的物理像素分辨率与CSS像素分辨率的比值。该值也可以被解释为像素大小的比例:即一个CSS像素的大小相对于一个物理像素的大小的比值。

那么我们增强一下我们上面的代码

console.log(screen.width * devicePixelRatio, '*', screen.height * devicePixelRatio)

现在可以输出 2736 * 1824 了。在我的 Mix 2S 上验证之后,发现可以得到接近真实的物理分辨率,但是仍然存在一些问题,因为 devicePixelRatio 为一个浮点数,乘以 screen.widthscreen.height 之后,得到结果可能为小数,且不知道向上取整还是向下取整更接近真实值。但是呢,这个精度其实已经够用啦。

如果检测用户是否缩放了页面?

由上面的讨论,我们发现 devicePixelRatio 这个属性在网页遭到缩放之后也会跟着改变。

// 系统 100% 缩放的 1080P 屏幕
console.log(devicePixelRatio)    // 网页 100% 缩放, 1
console.log(devicePixelRatio)    // 网页 140% 缩放, 1.4

// 系统 200% 缩放的 2K 屏幕
console.log(devicePixelRatio)    // 网页 100% 缩放, 2
console.log(devicePixelRatio)    // 网页 140% 缩放, 2.8

那么问题就来了,我们不知道得到一个 devicePixelRatio 是由系统全局缩放导致的,还是用户手动缩放导致的。

经过一番资料的查找,似乎没有对所有浏览器都兼容的优雅解法,也不能怪我每次用 Surface Pro 4 去打开斗鱼和 CSDN 的时候都提醒我缩放比例不对了。

网上的普遍做法都是先用 devicePixelRatio 做检测,如果浏览器不支持该属性,就退级到 outerWidthinnerWidth。对于 Chrome ,后者似乎有效可行,因为 outerWidth 不会受到缩放的影响,而 innerWidth 会受到缩放比例的影响。对于 Firefox,两个值都会受到缩放系数的影响。

// 2K 屏幕,系统 200% 缩放,浏览器 200% 缩放
// Chrome
console.log(outerWidth)    // 1368
console.log(innerWidth)    // 684

// Firefox
console.log(outerWidth)    // 691
console.log(innerWidth)    // 684, 其实这个值有些奇怪

当然,也存在特殊情况,如果浏览存在侧边栏,或者开发工具刚好打开在两侧,那么 innerWidthouterWidth 的比例就不那么单纯的意义明确了。

如何检测用户是否覆盖了页面字体的大小?

目前的智能手机都是可以调整系统全局字体大小的,PC 浏览器也可以强制覆盖我们 CSS 设置的字体,那么这时候如何判断字体是否和我们 CSS 指定的大小一样呢?

在文档中插入一个用于判定字体的 DOM 元素,设定字体大小为 initial

const defaultFontSize = '16px'
const textDom = document.querySelector('#text')
const style = window.getComputedStyle(textDom, null)

style['font-size'] === defaultFontSize

如果此时系统字体遭到了缩放,window.getComputedStyle() 查询到的是缩放后的字体大小值。

小结

这些问题看似简单但真的处理起来的时候需要有一定的经验和知识储备才能做好,这次写这篇文章感觉收获还是挺大的。