移动端页面自适应:用动态根字号 + rem 实现等比缩放

写移动端页面时,我在一个项目里用了一个很常见的自适应方案:根据屏幕宽度动态设置 htmlfont-size,然后页面尺寸尽量用 rem 来写。

这个方案在今天看不算新,但它很适合用来理解移动端自适应的底层思路:不是每个元素都单独计算,而是先确定一个页面基准,再让所有 rem 尺寸跟着根字号一起变化。

先看核心代码

在这个项目的很多 HTML 页面底部,都能看到这样一行代码:

document.getElementsByTagName("html")[0].style.fontSize =
  document.documentElement.clientWidth / 20 + "px";

它的意思是:

  1. 获取当前页面可视宽度:document.documentElement.clientWidth
  2. 把屏幕宽度分成 20 份
  3. 每一份作为 html 的根字号
  4. 页面中使用 rem 的尺寸,都会随着根字号变化

比如手机宽度是 375px

375 / 20 = 18.75

那么:

1rem = 18.75px

如果手机宽度是 320px

320 / 20 = 16

那么:

1rem = 16px

这样一来,同样写 10rem,在不同屏幕上的实际像素值就不同,页面比例也会跟着屏幕宽度变化。

为什么除以 20

这套写法本质上是把屏幕宽度抽象成 20rem

也就是说,不管用户手机宽度是多少,页面设计时都可以把整个屏幕宽度理解成:

width: 20rem;

如果一个元素宽度写成:

width: 10rem;

它就相当于占屏幕宽度的一半。

如果写成:

left: 2rem;
width: 16rem;

它就表示左右各留 2rem,中间内容占 16rem

在项目样式里可以看到这种写法:

.z-jihe {
  width: 16rem;
  position: absolute;
  top: 40%;
  left: 2rem;
}

.z-btnan {
  width: 12rem;
  margin-left: 4rem;
}

这两个例子都能看出一个设计习惯:页面宽度按 20rem 算,元素宽度和左右间距用 rem 分配。

viewport 也很关键

只设置根字号还不够,移动端页面通常还需要写 viewport:

<meta
  name="viewport"
  content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0"
>

这段的作用是告诉浏览器:页面宽度按设备宽度来,不要用默认的虚拟布局宽度。

如果没有这段,clientWidth 可能不是我们以为的手机实际宽度,后面的 clientWidth / 20 也就不准了。

所以这个方案的完整思路是:

viewport 控制页面视口
        ↓
JS 读取当前视口宽度
        ↓
设置 html 根字号
        ↓
CSS 用 rem 写尺寸
        ↓
不同屏幕下页面等比变化

这是不是 zoom 缩放

严格来说,这不是 CSS 的 zoom 缩放。

项目里确实有一段:

.clear {
  zoom: 1;
}

但这里的 zoom: 1 是早期常见的清除浮动写法,主要是为了触发旧版 IE 的 hasLayout,不是用来缩放整个页面。

真正让页面适配不同屏幕的,是这句:

document.documentElement.clientWidth / 20

再配合 CSS 里的 rem

所以更准确地说,这个项目用的是:

动态根字号 + rem 自适应

而不是:

zoom 缩放网页

一个具体例子

假设页面里有一个按钮:

.z-btnan {
  width: 12rem;
  margin-left: 4rem;
}

因为整个页面宽度被抽象成 20rem,所以:

  • 左边距 4rem
  • 按钮宽度 12rem
  • 右边剩余 4rem

按钮就会在页面中水平居中。

375px 屏幕上:

1rem = 18.75px
按钮宽度 = 12 * 18.75 = 225px
左边距 = 4 * 18.75 = 75px

320px 屏幕上:

1rem = 16px
按钮宽度 = 12 * 16 = 192px
左边距 = 4 * 16 = 64px

比例没变,只是实际像素变小了。

这就是 rem 自适应的核心。

当时这种写法的优点

这个方案有几个优点:

  1. 代码很少,一行 JS 就能确定全局缩放基准。
  2. 页面比例比较稳定,适合移动端活动页、商城页、表单页。
  3. 不依赖构建工具,普通 HTML 页面也能用。
  4. 对早期静态页面很友好,复制到多个页面就能生效。

在这个旧项目里,这行代码出现在很多页面中,说明它当时承担的是整套移动端页面的统一适配方案。

这个写法的问题

现在回头看,它也有一些明显问题。

第一,代码重复。每个页面都写一遍:

document.getElementsByTagName("html")[0].style.fontSize =
  document.documentElement.clientWidth / 20 + "px";

更好的方式是抽成一个公共 JS 文件。

第二,它只在页面加载时执行。如果用户旋转屏幕,或者窗口宽度变化,根字号不会自动重新计算。更完整的写法应该监听 resize

第三,所有屏幕都按比例缩放,不一定适合大屏。比如在平板或 PC 浏览器里,页面可能被放得过大。因此通常要设置一个最大宽度。

可以改成一个更完整的版本

如果现在手写,我会这样封装:

(function () {
  function setRootFontSize() {
    var docEl = document.documentElement;
    var width = docEl.clientWidth;

    // 避免在平板或 PC 上被无限放大
    if (width > 750) {
      width = 750;
    }

    docEl.style.fontSize = width / 20 + "px";
  }

  setRootFontSize();
  window.addEventListener("resize", setRootFontSize);
})();

这样做有三个改进:

  1. 封装成函数,方便复用。
  2. 页面尺寸变化时重新计算。
  3. 限制最大宽度,避免大屏过度放大。

和现代方案对比

现在做移动端自适应,常见选择更多:

  • rem:适合按设计稿比例缩放的移动端页面。
  • vw:可以直接按视口宽度计算,不需要 JS。
  • Flex/Grid:适合结构响应式,而不是整体等比缩放。
  • 媒体查询:适合不同屏幕下切换布局。

如果只是写一个移动端 H5 活动页,rem 方案仍然容易理解。如果是复杂应用,就不能只靠等比缩放,还要考虑内容流动、断点、组件布局和可读性。

总结

这段旧代码最有价值的地方,是它用非常少的代码解决了一个真实问题:不同手机屏幕宽度下,页面如何保持相近的视觉比例。

核心公式就是:

htmlFontSize = viewportWidth / 20

然后 CSS 用 rem 表达尺寸。

它不是严格意义上的 zoom 页面缩放,而是“动态根字号 + rem”的移动端自适应方案。理解了这个思路,再去看 lib-flexiblepx2remvw,就会轻松很多。

posted @ 2026-06-22 13:55  万物皆object  阅读(10)  评论(0)    收藏  举报