面试官:项目中rem是怎么使用的,你们一般设置多少?

其实这道题是一个简单的题,但是我当时回答的并不好,所以在此记录一下

核心回答框架

  1. 基础概念说明
  • REM 适配的本质是通过动态调整根元素的字体大小来实现页面元素的等比缩放,我们通过会将设计稿尺寸与REM单位建立可计算的映射关系。我们通常会将基础的html的font-size 设置成100px 或 50px

  • 移动端设计稿一般是750,100px 对应就是1rem

    ini 复制代码
        font-size = 设备宽度 * 100 / 750
        
js 复制代码
// flexible.js
(function () {
  function setRem() {
    const baseSize = 100; // 基础 `font-size`
    const designWidth = 750; // 设计稿宽度
    const scale = document.documentElement.clientWidth / designWidth;
    document.documentElement.style.fontSize = baseSize * scale + 'px';
  }
  setRem();
  window.addEventListener('resize', setRem);
})();

高级补充点(展现深度)

PostCSS 插件实现自动转换

我们喜欢设计稿是什么,直接CV过来,但是每次需要手动改动尺寸,然后我就引入postcss-pxtorem插件,让插件帮我们去实现转换这个过程。但是有一些特殊情况,在移动端1px 不同设备上渲染会出现不一致的粗细表现,比如border/box-shadow 那我们就要配置不去进行rem的转换

需要适配的阴影效果可以使用媒体查询单独调整

js 复制代码
.card {
  box-shadow: 2px 4px 10px rgba(0,0,0,0.1);
  
  @media (max-width: 375px) {
    box-shadow: 1px 2px 5px rgba(0,0,0,0.1);
  }
}

postCSS 相关完整配置

js 复制代码
// 进阶配置方案 postcss.config.js
module.exports = {
  plugins: {
    'postcss-import': {},
    'postcss-url': {},
    'postcss-preset-env': {
      browsers: 'last 2 versions',
      stage: 3,
      features: {
        'nesting-rules': true
      }
    },
    'postcss-pxtorem': {
      rootValue: 100,
      propList: [
        '*',
        '!border*', // 边框默认不转换
        '!box-shadow' // 阴影默认不转换
      ],
      selectorBlackList: [
        /^html$/,
        /^body$/,
        /^no-rem/
      ],
      mediaQuery: true,
      exclude: /node_modules/i
    },
    cssnano: {}
  }
}

Webpack 集成

js 复制代码
// webpack.config.js
module.exports = {
  module: {
    rules: [
      {
        test: /\.css$/,
        use: [
          'style-loader',
          'css-loader',
          {
            loader: 'postcss-loader',
            options: {
              postcssOptions: require('./postcss.config.js')
            }
          }
        ]
      }
    ]
  }
}

结合 scss / less 进行 rem 适配

如果项目里用了scss / less 完全可以不用postCSS

js 复制代码
@function rem($px) {
  @return ($px / 100) + rem;
}

/* 使用示例 */
.title {
  font-size: rem(40); // 40px -> 0.4rem
}

多主题的实现很REM 很像

js 复制代码
// 读取全部主题配置
const themeFileList: Record<string, string> = import.meta.glob(
  ['@/generated/theme/*.ts', '!@/generated/theme/theme-enum.ts'],
  {
    import: 'default',
    eager: true
  }
)
// 根据读取的文件路径,生成名称和地址
const themeFileListObject = {}
for (const key in themeFileList) {
  const filename = key.split('/').pop()?.replace('.ts', '')
  if (filename) {
    themeFileListObject[filename] = themeFileList[key]
  }
}

// 替换root样式
const injectRootStyle = (theme: ThemeEnum) => {
  const themeObject = themeFileListObject[theme]
  for (const key in themeObject) {
    document.documentElement.style.setProperty(key, themeObject[key])
  }
}

总结

以上就是我对REM 相关概念及实际应用的总结,从REM的基本概念以及换算公式,从而引入自动化css 单位转换,提供postcss-pxtorem 方案,并且解决1px 换算成0.01 像素在移动端展示粗细不一致的问题。并提供了完整的工程化配置

另外如果使用scss/less, 也可自定义方法函数实现这一转换

最后由动态font-size 又引到自己实现过的动态主题切换,殊途同归,都是利用 document.documentElement.style.xxx 去实现动态设置size / color 的功能

相关推荐
wdfk_prog7 小时前
嵌入式面试真题第 10 题:高优化等级下共享状态可见性、内存模型与系统级同步设计
java·linux·开发语言·面试·职场和发展·架构·c
胡萝卜术8 小时前
RAG 的知识炼油厂:从原始网页到可检索知识块的工程化之路
面试·架构·github
wdfk_prog8 小时前
嵌入式面试真题第 11 题:RTOS 优先级翻转与实时任务阻塞的通用治理
c语言·缓存·面试·职场和发展·架构
众人皆醒我独醉13 小时前
OpenShift RBAC 与平台安全策略:比 K8s 多出来的那几道锁,每道都是为了堵一个曾经发生过的事故
面试·kubernetes
众人皆醒我独醉14 小时前
为什么你的 RBAC 配了还是 403?—— 一套可以复现的排障方法论
面试·kubernetes
爱勇宝15 小时前
DeepSeek实习生日薪5500:真正恐怖的不是工资
人工智能·深度学习·面试
面试鸭15 小时前
面试官:“知识库搜到多少资料,你就全喂给 AI?”我:“信息越多越准。”她亮出错答案:“那它怎么被废话带跑了?”
后端·面试·求职
刘沅17 小时前
LeetCode 93.复原IP地址
算法·面试
用户409666013175117 小时前
实时数据大屏的 4 种推送方案:短轮询 → 长轮询 → SSE → WebSocket
后端·面试
不简说19 小时前
JS 代码技巧 vol.2 — 20 个数组/对象/字符串/正则的实用技巧
前端·javascript·面试