面试官:项目中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 的功能

相关推荐
uhakadotcom17 分钟前
DuckDB相比于ClickHouse有什么不同点和优势?
后端·面试·github
一只修仙的猿1 小时前
毕业三年后,我离职了
android·面试
加载中3612 小时前
pnpm时代包版本不一致问题还是否存在
前端·面试·npm
学历真的很重要3 小时前
Claude Code Windows 原生版安装指南
人工智能·windows·后端·语言模型·面试·go
yinke小琪3 小时前
消息队列如何保证消息顺序性?从原理到代码手把手教你
java·后端·面试
007php0074 小时前
某大厂MySQL面试之SQL注入触点发现与SQLMap测试
数据库·python·sql·mysql·面试·职场和发展·golang
kymjs张涛6 小时前
零一开源|前沿技术周刊 #15
前端·javascript·面试
UrbanJazzerati6 小时前
前端入门:vh、padding、margin、outline、pointer-events
前端·面试
沐怡旸6 小时前
【底层机制】std::unordered_map 扩容机制
c++·面试
沐怡旸6 小时前
【底层机制】auto 关键字的底层实现机制
c++·面试