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?
我的经验是,用一个“三问法则”快速判断:
-
这个值是否需要与视口宽度强关联?
- 是 → 用 rem(如容器宽度、间距、圆角半径)
- 否 → 进入第二问
-
这个值是否需要随父级文字大小等比缩放?
- 是 → 用 em(如行高、内边距、图标尺寸)
- 否 → 进入第三问
-
这个值是否需要绝对稳定、不受任何继承干扰?
- 是 → 用 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,执行以下操作:
-
在 Console 输入:
getComputedStyle(document.documentElement).fontSize // 输出 "100px"(初始值)或 "52.6667px"(iPhone 13) -
选中
.card-title元素,在 Styles 面板找到font-size: 1.5rem,右侧 Computed 面板会显示:
font-size: 78.9999px(因1.5 × 52.6667 = 78.9999) -
再选中
.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 计算链正确。 -
修改
.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,而非

710

被折叠的 条评论
为什么被折叠?



