PC 端网页缩放

网页缩放 zoom

前言

某个忙碌的下午,产品经理过来找我,“你这个页面被放得好大,显示的卡片你看都那么大个,用户没办法看呀”。

我表示很无奈呀,解释说这用户要放大那么多我也没办法,让用户把浏览器缩放一下就行了。但明显,这不是他想要的答案。的确,目前用户在笔记本上 windows 系统中放大 150% 很常见,这易导致一些页面展示的内容偏少,卡片和字体显得很大,但我们又不能要求用户修改一下放大倍数,这怎么办呢?

解决方案

根标签 font-size 加 rem 方案

这个方案是之前移动端很流行的解决方案,但是针对我们存量代码来说,不大可行,要进行大量修改;或者也可以配置 webpack 插件进行编译处理,但项目中各种单位都用,也难免会出现问题。暂时不考虑这个方案,因为我们后面还有更好的方案,嘻嘻。

viewport 方案

这个方案在移动端屡试不爽,在移动端配合 rem 使用也是之前淘宝流出的最佳实践,当年移动端全部都引入一个 flexible.js 文件,几乎所有的单位都可以用 rem 代替,很爽。

它是通过改变 meta viewport 标签的 scale 值去进行屏幕缩放的。但是,在 PC 端这个方案完全行不通,在 PC 端完全不支持 viewport 的 scale 值,绝望。

zoom 方案

后来想到了 zoom,zoom 属性与 transform 的 scale 属性类似,可以轻松处理元素的缩放。但它与 scale 也有明显的区别,zoom 的缩放只会缩放元素所占的空间大小,元素的布局也会跟着缩放。但是 scale 就不一样了,缩放时,元素所占的空间是不变的,原来的位置还会被占用,只缩放了元素的大小,这就很尴尬,缩小后会空出一大堆空间留白,没办法处理。

这样就选定 zoom 方案,看看实现吧。这里我们给定一些初始预期,我们希望被放得过大的屏幕,渲染效果不小于1750px 宽度的屏幕效果,举个例子,我们有一块1920宽度的屏幕,用户缩放倍数是 150%,那么 css 可布局像素实际最大只有 1920px / 150% = 1280px 的样子,这样距离我们预期 1750px 差距就出来了,我们只需要把 zoom 值缩小即可,看代码:

const zoom = 1280 / 1920
document.documentElement.style.zoom = zoom

非常简单对吧,把上面的代码改成自适应的:

const dpr = window.devicePixelRatio
const preferWidth = 1750
if (dpr > 1) { // 用户有放大,我们再做缩放
    const screenWidth = window.screen.width // 我们是针对屏幕进行缩放的,不是针对浏览器
    if (screenWidth < preferWidth) { // 屏幕小于预期值才执行
        const zoom = screenWidth / preferWidth // 得到缩放倍数
        document.documentElement.style.zoom = zoom
    }
}

这样我们就把屏幕缩小了,同时还检查用户是否放大,是否屏幕足够大等

跑起来,看着很完美。然后再检查一下,发现在有些元素的高度不够了,原来是占满屏幕高度的现在不占满了。

看了一下,是由于设置了 100vh 高度的原因,原来的 100vh 可以占满屏幕,现在元素缩写了,100vh 占不满屏幕了,怎么办呢?

想到的办法是在编写 100vh 的地方更改一下,例如:

.sample-class {
    /* height: 100vh; */
    height: calc(100vh / var(--zoom))
}

我们让 100vh 除以 zoom 值就可了 这个zoom值可以用下面的方式从 js 中暴露出来

const dpr = window.devicePixelRatio
const preferWidth = 1750
let zoom = 1
if (dpr > 1) { // 用户有放大,我们再做缩放
    const screenWidth = window.screen.width // 我们是针对屏幕进行缩放的,不是针对浏览器
    if (screenWidth < preferWidth) { // 屏幕小于预期值才执行
        zoom = screenWidth / preferWidth // 得到缩放倍数
        document.documentElement.style.zoom = zoom
    }
}

document.documentElement.style.setProperty('--zoom', zoom)
document.documentElement.style.setProperty('--full-height', window.innerHeight)

css 中使用:

.sample-class {
    height: calc(100vh / var(--zoom))
}

.sample-class2 {
    height: var(--full-height)
}

当然,你需要在屏幕大小变动时重新设置 --full-height

window.addEventListener('resize', () => {
    document.documentElement.style.setProperty('--full-height', window.innerHeight)
})

或者设置值时就用 vh

// ...省略以上代码
document.documentElement.style.setProperty('--full-height', 100 / zoom + 'vh' )

这样在使用到 100vh 后者 100vw 的地方,修改一下就行了,幸运的时我的项目中并没有几处需要修改。完美!

以上的方法是针对屏幕的尺寸进行缩放的,不是浏览器,如果你要针对浏览器进行缩放,相应的修改 screenWidth 值为 window.innerWidth 即可,以上是伪代码,只是提供解决思路。直接抄的话请自行测试是否有错误哦。

兼容性

font-size 和 rem 方案都有比较强的兼容性,但 zoom 的兼容性不是特别好,兼容 IE、Chrome、Safari、Edge 浏览器,不兼容 Firefox。

caniuse caniuse-zoom.PNG

评论

0/500

全部评论 (1)

  • lithoge (作者) 2021-11-06 16:40:28

    后面发现了问题,Echarts 等图标插件并不兼容 zoom 缩放,会导致缩放后的图标鼠标焦点错位的问题,应该是由于我们进行了缩放,但计算鼠标位置的方法并不会考虑 zoom 缩放的情况导致。为了解决这个问题,尝试了把 echarts 容器设置 zoom: calc(1 / zoom) 放大回去,但是这样又会出现图标渲染又会出现问题。后面在 cnblog 发现可以通过 zoom 放大,transform scale 缩小的方法,的确解决了大多数问题,但依然有少部分图表元素位置微微错位,不过会影响不大,就暂时用此方案。一些其他图标如 antd/g2、maxbox 只需要设置 zoom 放大到原来的大小即可正常渲染,完美解决鼠标焦点问题。

    0
    /