分析 Flexible.js + postCssPxToRem 的响应式布局的原理

126 阅读2分钟

前言:
之前在项目中引入 flexible.js 这个包,并在vite脚手架中安装了 postCssPxToRem 这个打包插件后,我的H5项目就能根据屏幕宽度缩放,自动调整页面上所有UI元素的大小。这非常神奇。所以我决定探究一下其原理。

  1. 打包阶段:
    postCssPxToRem插件用于将CSS中的PX转换为REM。
    那么我们如何指定,40px该转换为多少Rem呢?
    这就用到了postCaaPxToRem插件的 “rootValue” 属性。
    举例,这里我们将rootValue设为41.4,这里的语义是:“打包代码时,我们假定1Rem等于41.4px”
    所以,在以下的配置下,40px会被转换为40 / 41.4 = 0.966183rem

    postCssPxToRem({
        rootValue: 41.4,
        propList: ["*"],
    })
    

    现在我们打包出来的代码,所有的UI元素都是以REM为单位的了。

  2. 浏览器运行阶段:
    在实际浏览器代码执行中,REM这个单位实际上是 “Font size of the root element.”
    意思就是说:n Rem 就是 n * 根元素的font-size
    这套方案效果是,我们在缩小屏幕宽度的时候,把UI元素等比例缩小。
    所以,我们只需要监听window的“resize“事件,在resize发生时,获取当前window的宽度,并根据window的宽度重新计算并设定根元素的font-size。

    此时,因为页面上所有UI元素都以“REM“为单位,我们一旦手动重新设定根元素的”font-size“,那么就改变了整个页面上所有的UI大小。实现了响应式缩放。

    下面是flexible.js监听window resize并重新设定根元素font-size的的核心代码:

      win.addEventListener(
        'resize',
        function () {
          clearTimeout(tid);
          tid = setTimeout(refreshRem, 300);
        },
        false,
      );
    
      function refreshRem() {
        var width = docEl.getBoundingClientRect().width;
        // 设计稿为414,计算rem最大宽度不能大于414
        if (width / dpr > 414) {
          width = 414 * dpr;
        }
        var rem = width / 10;
        docEl.style.fontSize = rem + 'px';
        flexible.rem = win.rem = rem;
      }
    
  3. 参考文献:
    CSS values and units - Learn web development | MDN (mozilla.org) 介绍了REM单位的定义