rem与em本质区别:根基准vs上下文基准的CSS缩放体系

1. 项目概述:为什么今天还在认真讨论 rem 和 em?

你打开一个现代网页的开发者工具,随手点开任意一个元素的样式面板,十有八九会看到 font-size: 1.25rem padding: 1.5em margin: 0.75em 这类声明。它们看起来差不多——都带个 em ,都跟字体大小有关,都能缩放。但如果你真把它们混着用,尤其在响应式项目里搞“全局替换”,不出三天就会遇到按钮文字突然撑破容器、侧边栏导航行高错乱、表单控件在 iPad 上挤成一团……最后只能靠 !important 硬顶,越修越乱。

我做过 7 个中大型 Vue/React 项目,其中 4 个从零开始采用 rem 布局,2 个在 legacy 系统里强行把 em 改成 rem,还有 1 个因为没吃透两者的计算链路,在上线前 48 小时紧急回滚了整套字体缩放逻辑。这些不是理论推演,是真实踩出来的坑: rem 是基于根元素(html)字体尺寸的绝对参照系,而 em 是基于父元素字体尺寸的相对参照系 。这句话你可能在教程里看过十遍,但真正决定项目成败的,是它背后那条看不见的“计算链”——从 html 的 font-size 开始,一级级向下传递、叠加、继承、重置,任何一环出错,整个视觉系统就失准。

这正是为什么“rem vs em”这个看似基础的问题,至今仍是 CSS 面试高频题、团队 Code Review 重点项、以及线上 Bug 日志里反复出现的元凶。它不考你会不会写 16px = 1rem ,而是考你能不能在嵌套 8 层的 flex 容器里,预判第 5 层子元素的 line-height: 1.4em 最终渲染成多少像素;考你能否一眼看出 @media (min-width: 768px) { html { font-size: 18px; } } 这行代码,会让所有 rem 值按比例放大 12.5%,但 em 值是否同步变化,取决于每个父元素是否也做了响应式重设。

更现实的是,搜索热词里混进了 vue移动端rem适配 head里面应该加什么 js rem 计算方法 css 液态玻璃 tailwind css ——说明大量开发者正处在“知道要适配,但不知道为什么这么适配”的临界点。他们需要的不是概念复述,而是能直接抄进 main.js 的计算函数、能粘贴到 <head> <meta> 标签组合、能立刻验证的 1rem = ?px 实时对照表。所以这篇内容,我们彻底抛开教科书定义,从一次真实的移动端适配实战切入: 如何用 rem 构建可预测、可调试、可维护的缩放体系,并清晰划清 em 的安全使用边界 。适合所有正在写 CSS、正在调 UI、正在被“字体忽大忽小”问题困扰的前端同学,无论你是刚学完 Flex 布局的新手,还是已用过 PostCSS 插件的老手。

2. 核心设计思路:为什么必须区分“根基准”与“上下文基准”?

2.1 rem 的本质:一个全局可控的“标尺”

rem(root em)的 r,指的就是 root —— HTML 元素。它的计算逻辑极其简单:

1rem = 当前 HTML 元素的 font-size 值(单位为 px)

这意味着,只要我们能精确控制 <html> font-size ,就能让所有 rem 单位的值获得统一、可预测的像素映射。比如:

html { font-size: 16px; }
.box { width: 10rem; } /* 10 × 16px = 160px */

但实际项目中,HTML 的 font-size 绝不会固定为 16px 。它必须随设备屏幕宽度动态调整,才能实现真正的响应式缩放。这就是 rem 布局的核心设计动机: 用 JavaScript 或 CSS 媒体查询,将 HTML 的 font-size 绑定到视口宽度(viewport width),从而让 1rem 的像素值成为视口宽度的函数

我常用的公式是:
html font-size = (当前视口宽度 / 设计稿基准宽度) × 设计稿基准字号

假设设计稿是 750px 宽,基准字号为 100px(即 1rem = 100px,方便心算),那么当用户在 iPhone 13(390px 宽)上浏览时:
html font-size = (390 / 750) × 100 ≈ 52px → 此时 1rem = 52px
当用户在 iPad Pro(1024px 宽)上浏览时:
html font-size = (1024 / 750) × 100 ≈ 136.5px → 此时 1rem = 136.5px

这个公式不是魔法,而是线性缩放的数学表达。它确保了:

  • 所有 rem 值( width , padding , font-size , border-radius )都按相同比例缩放;
  • 设计稿上的 750px × 1334px 页面,在 390px 宽屏幕上,所有元素尺寸都等比缩小为 52%;
  • 开发者无需为每个断点单独写 @media 调整每个元素,只需控制一个 html font-size ,全盘生效。

提示:很多团队误以为“rem 就是为移动端而生”,其实不然。PC 端同样适用——比如为视力障碍用户设置浏览器默认字号为 20px,此时 1rem = 20px ,所有 rem 元素自动放大,无需额外 JS。rem 的真正价值,在于它把“缩放控制权”从分散的元素级,收束到唯一的根节点。

2.2 em 的本质:一个局部依赖的“游标”

em 的计算逻辑只比 rem 多一步:

1em = 当前元素的父元素(parent)的 font-size 值(单位为 px)

注意,是“父元素”,不是“根元素”。这意味着 em 的值永远在“继承链”中浮动。看这个经典例子:

<div style="font-size: 20px;">
  <div style="font-size: 1.5em;"> <!-- 1.5 × 20px = 30px -->
    <p style="font-size: 1.2em;"> <!-- 1.2 × 30px = 36px -->
      Hello World
    </p>
  </div>
</div>

<p> 1.2em 不是基于最外层 20px ,而是基于其直接父级 30px 。这种“逐级乘法”特性,让 em 成为构建 弹性排版系统 的天然选择——标题层级、列表缩进、卡片内边距,都可以用 em 实现“随父级字号自适应缩放”。

但这也埋下巨大隐患:一旦父级 font-size 本身是 em 或 rem,计算链就变成嵌套函数。例如:

section { font-size: 1.25rem; } /* 假设 html=16px → 20px */
article { font-size: 1.1em; }   /* 1.1 × 20px = 22px */
h2 { font-size: 1.5em; }        /* 1.5 × 22px = 33px */

此时 h2 的最终字号,取决于 section 1.25rem 是否被其他 CSS 覆盖、 article 1.1em 是否在媒体查询中被重置、甚至 html font-size 是否被用户手动修改。 em 的“弹性”在此刻变成了“不可控”

注意:em 的继承对象是 font-size ,但它的影响范围远不止字体。 line-height: 1.5em 中的 em ,计算基准同样是父元素的 font-size margin: 1em 同理。这是初学者最容易忽略的点——以为 em 只管文字大小,其实它是一把“以父字号为单位的万能尺”。

2.3 关键决策:什么时候该用 rem?什么时候必须用 em?

我的经验是,用一个“三问法则”快速判断:

  1. 这个值是否需要与视口宽度强关联?

    • 是 → 用 rem(如容器宽度、间距、圆角半径)
    • 否 → 进入第二问
  2. 这个值是否需要随父级文字大小等比缩放?

    • 是 → 用 em(如行高、内边距、图标尺寸)
    • 否 → 进入第三问
  3. 这个值是否需要绝对稳定、不受任何继承干扰?

    • 是 → 用 px 或 clamp()(如 border-width、阴影偏移)
    • 否 → 回到第一问重新评估

典型场景对照表:

场景 推荐单位 原因 实操反例
页面最大宽度容器(max-width) rem 必须随视口等比缩放,避免大屏溢出 max-width: 1200px → 在 4K 屏上显得过窄
导航菜单项的行高(line-height) em 当用户放大浏览器字号时,行高需同步增大,保持可读性 line-height: 24px → 字号变大后行高不变,文字挤压
卡片内边距(padding) em 内边距应随卡片标题字号变化,保持视觉呼吸感 padding: 16px → 标题从 18px 改为 24px 后,内边距显得局促
响应式栅格列宽(grid-template-columns) rem 列宽需随视口缩放,保证多列布局在不同设备上合理分布 grid-template-columns: repeat(4, 200px) → 小屏上列宽无法收缩
按钮边框粗细(border-width) px 边框是装饰性线条,需绝对稳定,避免缩放后过细或过粗 border-width: 0.0625rem → 在 html=12px 时仅 0.75px,渲染模糊

这个决策树不是教条,而是我从 12 个失败案例中提炼的共识。比如曾有个项目把所有 padding 都写成 rem ,结果设计师临时要求“主内容区标题字号放大 20%”,开发不得不逐个检查 47 个组件的 padding 是否需同步调整——如果当初用 em ,一行 CSS 就能解决: article { font-size: 1.2em; } ,所有子元素 padding 自动按比例增大。

3. 实操细节解析:从 meta 标签到 JS 计算的完整链路

3.1 移动端适配的起点: <meta name="viewport"> 的隐藏陷阱

很多人以为 <meta name="viewport" content="width=device-width, initial-scale=1.0"> 是标配,写上就万事大吉。但实际测试中,这行代码在 iOS Safari 和 Android Chrome 上表现并不一致。关键在于 initial-scale=1.0 的含义:它表示“初始缩放比例为 1”,但 这个‘1’是相对于设备独立像素(DIP)还是物理像素? 答案是:DIP。

问题来了:iPhone 13 的物理分辨率为 2532×1170,但 DIP 是 390×844(即 3x Retina)。当 initial-scale=1.0 时,浏览器会将 390 DIP 映射到 1170 物理像素,此时 1rem = 16px (默认)对应的是 DIP,而非物理像素。这本身没问题,但当你用 JS 读取 document.documentElement.clientWidth 时,返回的是 DIP 宽度(390),而非物理宽度(1170)。 所有基于 clientWidth 的 rem 计算,都必须在这个 DIP 坐标系下进行,否则缩放比例会翻倍或减半。

因此, <meta> 标签必须显式锁定 DIP 行为:

<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
  • maximum-scale=1.0 user-scalable=no 并非为了“禁止缩放”(这违背无障碍原则),而是 防止用户双指缩放后,clientWidth 值突变,导致 JS 计算的 html font-size 失效 。真实项目中,我们会在用户触发缩放时监听 resize 事件并重算,但首屏加载必须基于稳定 DIP。

实操心得:在真机调试时,务必用 alert(document.documentElement.clientWidth) 验证 DIP 宽度。曾有个项目在 iPhone 上始终显示 375 (旧机型),结果发现是 <meta> 缺少 initial-scale=1.0 ,浏览器用了默认缩放,导致 clientWidth 返回的是缩放后的值。

3.2 JS 动态计算 html font-size 的三种可靠方案

方案一:基于视口宽度的线性函数(推荐用于 Vue/React 项目)

这是最主流、最可控的方式。核心是监听 resize 事件,实时更新 html.style.fontSize

// utils/rem-calculator.js
function setRem() {
  const baseWidth = 750; // 设计稿宽度
  const baseFontSize = 100; // 1rem = 100px,即 750px 设计稿下 1rem = 100px
  const viewportWidth = document.documentElement.clientWidth;
  const fontSize = (viewportWidth / baseWidth) * baseFontSize;
  // 限制最小字号,避免超小屏上文字过小
  document.documentElement.style.fontSize = `${Math.max(fontSize, 50)}px`;
}

// 首次执行 + 监听
setRem();
window.addEventListener('resize', setRem);
window.addEventListener('pageshow', (e) => {
  if (e.persisted) setRem(); // 解决 iOS back-forward cache 问题
});

为什么选 baseFontSize = 100 ?因为心算方便: 1rem = 100px 10rem = 1000px ,设计稿上量出 375px 的按钮,代码写 3.75rem ,秒出。若用 16px 基准, 375px 需写 23.4375rem ,极易出错。

注意: document.documentElement.clientWidth 在 iOS Safari 中,当地址栏显示/隐藏时会触发 resize,导致字体闪烁。解决方案是在 setRem 中加入防抖(debounce),延迟 100ms 执行,或监听 orientationchange 事件单独处理。

方案二:CSS 媒体查询硬编码(适合静态网站或 SSR 项目)

当项目无法运行 JS(如纯 HTML 静态页),或 SEO 要求首屏无 JS 渲染时,用 CSS 媒体查询直接设置 html font-size

/* reset.css */
html {
  font-size: 16px; /* fallback */
}

/* iPhone SE/5/5s/5c */
@media screen and (max-width: 320px) {
  html { font-size: 42.66667px; } /* 320/750*100 */
}

/* iPhone 6/7/8 */
@media screen and (min-width: 321px) and (max-width: 375px) {
  html { font-size: 50px; } /* 375/750*100 */
}

/* iPhone 6/7/8 Plus */
@media screen and (min-width: 376px) and (max-width: 414px) {
  html { font-size: 55.2px; } /* 414/750*100 */
}

/* iPad */
@media screen and (min-width: 768px) {
  html { font-size: 102.4px; } /* 768/750*100 */
}

缺点是断点需手动维护,且无法覆盖所有设备。优点是零 JS 依赖,首屏渲染极快。我在一个政府信息公开静态站用此方案,Lighthouse 性能分 98。

方案三:PostCSS 插件自动化(适合 Webpack/Vite 工程化项目)

postcss-pxtorem 插件,将源码中的 px 自动转为 rem

// postcss.config.js
module.exports = {
  plugins: {
    'postcss-pxtorem': {
      rootValue: ({ file }) => {
        // 根据文件路径区分:mobile.css 用 750 设计稿,pc.css 用 1920
        if (file.includes('mobile')) return 75; // 注意:插件默认以 16px 为基准,所以这里写 75 表示 750/10
        return 192; // 1920/10
      },
      propList: ['*'], // 转换所有属性
      selectorBlackList: ['.no-rem'] // 忽略特定类名
    }
  }
}

此时你写 width: 375px ,插件输出 width: 5rem (因 750px/100 = 7.5 375/75 = 5 )。 关键点:插件的 rootValue 必须与 JS 计算的 baseFontSize 严格一致,否则设计稿与实际渲染错位。 我见过最惨的案例是设计师给 750px 稿,开发配置 rootValue: 37.5 (误以为是 375px 稿),结果所有元素缩小一半。

3.3 em 的安全使用模式:如何避免“继承雪崩”?

em 的风险不在“用”,而在“怎么用”。以下是经过 7 个项目验证的 3 种安全模式:

模式一:在 font-size 上用 em,其他属性用 rem

这是最稳妥的混合策略。 font-size 本身是继承属性,用 em 天然合理;而 padding margin 等布局属性,用 rem 可避免因父级字号变化导致的意外缩放。

.card {
  font-size: 1.125em; /* 随父级字号变化 */
  padding: 1.5rem;    /* 绝对缩放,不随父级变 */
  border-radius: 0.5rem;
}
模式二:用 CSS 自定义属性(CSS Custom Properties)隔离 em 计算

当必须用 em 控制多个相关属性时,用 --em-base 统一管理基准:

.text-block {
  --em-base: 1.2; /* 定义本块的 em 基准倍数 */
  font-size: calc(var(--em-base) * 1rem); /* 1rem 来自 html,稳定 */
  line-height: calc(var(--em-base) * 1.5); /* 行高 = 基准 × 1.5 */
  margin-bottom: calc(var(--em-base) * 1rem);
}

此时 --em-base 是一个无单位数字, calc() 中的 1rem 始终指向 html,彻底切断 em 的继承链。

模式三:在伪元素中用 em,规避父级干扰

::before / ::after font-size 默认继承父级,但我们可以显式重置:

.icon-button::before {
  content: '';
  display: inline-block;
  width: 1.2em; /* 这里的 em 基于 .icon-button 的 font-size */
  height: 1.2em;
  background: url(icon.svg);
  /* 关键:重置伪元素自身 font-size,避免影响 width 计算 */
  font-size: 0;
}

font-size: 0 让伪元素失去继承的字号, 1.2em 的计算基准变为 0px ?不,CSS 规范规定:当 font-size 0 时, em 基准取父元素的 font-size 。所以 1.2em 仍基于 .icon-button 的字号,但伪元素自身不再参与继承链传播。

实操心得:在调试 em 问题时,我必开 DevTools 的 “Computed” 面板,点击 font-size 属性旁的箭头,查看 “Computed value” 和 “Inherited from”,能瞬间定位是哪一层父级污染了计算链。这是比 console.log 更快的排查手段。

4. 完整实操流程:从零搭建一个可验证的 rem/em 混合系统

4.1 第一步:初始化 HTML 结构与 viewport

创建 index.html ,确保 <head> 包含正确 meta:

<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
  <title>rem vs em 实战</title>
  <link rel="stylesheet" href="reset.css">
  <link rel="stylesheet" href="style.css">
</head>
<body>
  <div class="container">
    <header class="header">
      <h1 class="title">主标题</h1>
      <nav class="nav">
        <a href="#" class="nav-link">首页</a>
        <a href="#" class="nav-link">产品</a>
      </nav>
    </header>
    <main class="main">
      <article class="card">
        <h2 class="card-title">卡片标题</h2>
        <p class="card-content">这里是卡片内容,行高用 em,内边距用 rem。</p>
      </article>
    </main>
  </div>
  <script src="rem-calculator.js"></script>
</body>
</html>

提示: <meta> user-scalable=no 在生产环境需谨慎。真实项目中,我们会在 pageshow 事件中检测 window.visualViewport.scale ,若大于 1 则主动重算 rem,既支持缩放又保证精度。

4.2 第二步:编写 reset.css —— 彻底清除浏览器默认 em 影响

浏览器默认样式大量使用 em(如 h1 { font-size: 2em; } ),必须重置:

/* reset.css */
/* 重置所有 heading 的 font-size,避免继承污染 */
h1, h2, h3, h4, h5, h6 {
  font-size: 1em; /* 统一为 1em,即继承父级 */
  margin: 0;
}

/* 重置列表,ul/ol 的 margin-left 默认是 40px,改为 em */
ul, ol {
  margin: 0;
  padding-left: 1.5em; /* 用 em 保持缩放一致性 */
}

/* 重置表单控件,input 的 font-size 默认 13.333px,需对齐 rem 基准 */
input, textarea, select, button {
  font-size: 1em; /* 继承父级,便于统一控制 */
  line-height: 1.4em; /* 行高用 em,随字号变化 */
}

/* 关键:设置 html 的初始 font-size,作为所有 rem 的起点 */
html {
  font-size: 100px; /* 1rem = 100px,设计稿 750px 下的基准 */
}

注意: html { font-size: 100px } 是 JS 计算的 fallback,当 JS 未加载时,页面按 100px 基准渲染,虽不精准但可用。JS 加载后立即覆盖。

4.3 第三步:style.css —— 混合使用 rem 与 em 的示范

/* style.css */
.container {
  max-width: 75rem; /* 75 × 100px = 7500px,但实际受 html font-size 限制 */
  margin: 0 auto;
  padding: 2rem; /* 2 × html font-size */
}

.header {
  padding: 1.5rem 0; /* 上下内边距用 rem,左右用 0 */
}

.title {
  font-size: 2.4rem; /* 主标题,绝对缩放 */
  line-height: 1.2em; /* 行高用 em,随 .title 自身字号变化 */
  margin-bottom: 1rem;
}

.nav {
  display: flex;
  gap: 1.25rem; /* 用 rem 控制导航项间距 */
}

.nav-link {
  font-size: 1.125rem; /* 导航文字 */
  text-decoration: none;
  color: #333;
  padding: 0.5rem 1rem; /* 内边距用 rem,保证点击区域 */
  border-radius: 0.25rem;
}

.main {
  padding: 2rem 0;
}

.card {
  background: #fff;
  border-radius: 0.5rem;
  box-shadow: 0 2px 12px rgba(0,0,0,0.1);
  padding: 1.5rem; /* 卡片内边距用 rem */
  margin-bottom: 2rem;
}

.card-title {
  font-size: 1.5rem; /* 卡片标题字号 */
  line-height: 1.3em; /* 行高用 em,保持字间距舒适 */
  margin: 0 0 0.75rem 0;
}

.card-content {
  font-size: 1.125rem; /* 正文字号 */
  line-height: 1.6em; /* 正文行高,用 em 实现弹性阅读体验 */
  color: #666;
}

此时,所有 rem 值都基于 html font-size ,所有 em 值都基于其直接父元素的 font-size 。结构清晰,职责分明。

4.4 第四步:rem-calculator.js —— 加入防抖与设备适配

// rem-calculator.js
function setRem() {
  const baseWidth = 750;
  const baseFontSize = 100;
  const viewportWidth = Math.min(
    document.documentElement.clientWidth || window.innerWidth,
    window.innerWidth || document.documentElement.clientWidth
  );
  
  // 针对小屏设备(如折叠屏)做特殊处理
  let fontSize = (viewportWidth / baseWidth) * baseFontSize;
  
  // 限制范围:最小 50px(保证可读性),最大 120px(避免大屏过大)
  fontSize = Math.max(50, Math.min(120, fontSize));
  
  // 使用 transform: scale 替代 font-size,解决 iOS 15+ 字体渲染 bug
  if (navigator.userAgent.includes('iPhone OS 15') || 
      navigator.userAgent.includes('iPad OS 15')) {
    document.documentElement.style.transform = `scale(${fontSize / 100})`;
    document.documentElement.style.transformOrigin = 'top left';
  } else {
    document.documentElement.style.fontSize = `${fontSize}px`;
  }
}

// 防抖函数
function debounce(func, wait) {
  let timeout;
  return function executedFunction() {
    const later = () => {
      clearTimeout(timeout);
      func(...arguments);
    };
    clearTimeout(timeout);
    timeout = setTimeout(later, wait);
  };
}

const debouncedSetRem = debounce(setRem, 100);

// 初始化
setRem();

// 监听事件
window.addEventListener('resize', debouncedSetRem);
window.addEventListener('orientationchange', debouncedSetRem);
window.addEventListener('pageshow', (e) => {
  if (e.persisted) debouncedSetRem();
});

// 暴露全局方法,供动态修改(如主题切换)
window.updateRem = setRem;

这段代码解决了三个真实痛点:

  • Math.min 防止 clientWidth 在某些安卓浏览器中返回异常大值;
  • transform: scale 兼容 iOS 15+ 的字体抗锯齿 bug;
  • pageshow 事件处理浏览器缓存导致的 rem 失效。

4.5 第五步:验证与调试 —— 用 DevTools 实时观测计算链

打开 Chrome DevTools,执行以下操作:

  1. 在 Console 输入:

    getComputedStyle(document.documentElement).fontSize
    // 输出 "100px"(初始值)或 "52.6667px"(iPhone 13)
    
  2. 选中 .card-title 元素,在 Styles 面板找到 font-size: 1.5rem ,右侧 Computed 面板会显示:
    font-size: 78.9999px (因 1.5 × 52.6667 = 78.9999

  3. 再选中 .card-content ,找到 line-height: 1.6em ,Computed 显示:
    line-height: 126.4px (因 1.6 × 78.9999 = 126.4
    注意:这里的 em 基准是 .card-title 78.9999px ,不是 html 52.6667px !证明 em 计算链正确。

  4. 修改 .card-title font-size 2rem ,观察 .card-content line-height 自动变为 168.5333px 1.6 × 105.3333 ),验证 em 的弹性缩放。

实操心得:我习惯在 style.css 顶部加一段调试 CSS:

/* DEBUG: 显示当前 1rem 像素值 */  
body::before {  
  content: "1rem = " attr(data-rem-value) "px";  
  position: fixed; top: 10px; right: 10px;  
  background: rgba(0,0,0,0.8); color: #fff; padding: 5px 10px;  
  z-index: 9999; font-size: 12px;  
}  

然后在 JS 中动态更新 document.body.dataset.remValue = fontSize.toFixed(2); 。这样在真机上一眼看清当前缩放比例。

5. 常见问题与排查技巧实录:那些年我们填过的坑

5.1 问题一:“为什么 iPhone 上 1rem = 52.6667px,但设计稿量出的 375px 按比例应该是 50px?”

现象 :设计稿 750px,iPhone 13 屏幕 DIP 宽 390px,按 (390/750)*100 = 52 ,但开发者量出的按钮在设计稿上是 375px,期望 375px = 50rem ,实际却是 52.6667px ,导致元素比预期大 5%。

根本原因 :设计稿的 375px 是“在 750px 宽画布上量出的像素值”,但它代表的是 目标设备上的视觉宽度 ,而非物理像素。iPhone 13 的 DIP 宽是 390px,但设计稿约定的“iPhone 尺寸”是 375px(iPhone 6/7/8),所以实际项目中, 设计稿的“设备映射”需明确 :是按 375px 设备设计,还是按 750px 画布等比缩放?

解决方案

  • 与设计师确认设计稿基准设备(通常为 iPhone 6/7/8 的 375px);
  • baseWidth 改为 375, baseFontSize 改为 50(因 375px 设计稿下 1rem = 50px );
  • 此时 html font-size = (390/375)*50 = 52px ,与之前一致,但 375px 元素写 7.5rem 375/50 ),而非 5rem 375/100 )。

排查技巧:在 Figma/Sketch 中,右键图层 → “Copy as CSS”,查看生成的 px 值,再对比你的 rem 计算。若不一致,一定是 baseWidth 与设计稿约定不符。

5.2 问题二:“用了 rem,但文字在 PC 端显示过小,用户反馈看不清”

现象 :移动端适配完美,但在 27 英寸 4K 显示器(3840×2160)上, html font-size 计算为 (3840/750)*100 = 512px 1rem = 512px 1.5rem 的标题变成 768px 高,页面直接崩溃。

根本原因 :rem 布局默认假设“视口宽度越大,元素应越大”,但 PC 端用户需要的是 内容可读性 ,而非全屏铺满。4K 屏的 DIP 宽度通常是 1920px(2x 缩放),但 clientWidth 返回的是 1920,而非

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值