rem适配 - 简单讲解和案例(超详细小白修订版)
本文是早年旧文的修订版。原博客有几个换算注释写错、还有一张本地图片发到线上就 404 了,这里一并修掉,并补全了「px 怎么换算成 rem」「现代动态适配」两块内容,目标是让纯小白也能照着抄会。
🤔 一、什么是 rem?为什么要用它?
rem是 CSS 的一个长度单位,它的大小永远跟着<html>(根元素)的font-size走。
1rem= 根元素font-size的 1 倍- 根
font-size: 16px时,1rem = 16px - 根
font-size: 50px时,1rem = 50px
那它和px比有啥用?当你把页面里所有尺寸都写成rem,再动态改根元素的font-size,整页就会按比例一起放大缩小——这就是「rem 适配」的核心,专门用来做不同手机屏幕的等比缩放。
em是相对"父元素"字号,rem是相对"根元素"字号。做适配一律用rem,更可控。
📐 二、核心思路(一句话讲明白)
用媒体查询(或 JS)根据不同屏幕宽度,按比例设置
<html>的字号;然后页面里所有元素都用rem当尺寸单位。根字号一变,所有rem元素跟着变,于是整页等比缩放,完成适配。
🧮 三、px 怎么换算成 rem?(重点,原博客没讲清)
这是小白最容易卡住的地方,记住一个公式就够了。
假设你的设计稿宽度是 750px(移动端最常见),我们把宽度分成 15 份:
1rem = 设计稿宽度 / 份数 = 750 / 15 = 50px所以在「设计稿宽度下」,1rem = 50px。任意 px 转 rem 就是:
rem = px值 ÷ 50| 设计稿上的 px | 换算成 rem |
|---|---|
| 50px | 1rem |
| 37.5px | 0.75rem |
| 16px | 0.32rem |
| 100px | 2rem |
| 25px | 0.5rem |
⚠️常见误区:很多人以为0.32rem在任何屏幕都是 16px。错!rem是相对的——只有根字号 = 50px 时它才是 16px。屏幕变窄根字号变小,0.32rem也会跟着变小(比如根字号 25px 时,0.32rem = 8px)。原博客就是把这里注释写成了"12px",实际是 8px,已修正。
✂️ 四、方法一:媒体查询手动适配(最原始,适合理解)
先上一份修正过错误注释的完整可运行代码:
<!DOCTYPEhtml><htmllang="zh-CN"><head><metacharset="UTF-8"><metahttp-equiv="X-UA-Compatible"content="IE=edge"><!-- 这一行必须加!否则手机不会按设备宽度渲染 --><metaname="viewport"content="width=device-width, initial-scale=1.0"><title>rem 适配演示</title><style>body{margin:0;padding:0;}/* 把屏幕分成 15 份,字号 = 屏幕宽度 / 15 *//* 注意:要写 min-width 和 max-width 兜底,否则 PC 端会回退到默认 16px */@mediaonlyscreenand(min-width:751px){html{font-size:50px;}/* PC / 大屏:固定 50px,不让字无限大 */}@mediaonlyscreenand(max-width:750px){html{font-size:50px;}/* 750px:750/15 = 50px */}@mediaonlyscreenand(max-width:414px){html{font-size:27.6px;}/* 414px:414/15 = 27.6px */}@mediaonlyscreenand(max-width:375px){html{font-size:25px;}/* 375px:375/15 = 25px */}/* 下面全部用 rem,跟着根字号走 */.title{font-size:0.75rem;}/* 750宽=37.5px,414宽=20.7px,375宽=18.75px */.content{font-size:0.32rem;}/* 750宽=16px, 414宽=8.83px,375宽=8px */img{width:1rem;}/* 750宽=50px */.box1{width:1rem;height:1rem;background:antiquewhite;}.box2{width:2rem;height:2rem;background:antiquewhite;}.box3_75{width:3.75rem;height:3.75rem;background:antiquewhite;}.box7_5{width:7.5rem;height:7.5rem;background:antiquewhite;}.box15{width:15rem;height:15rem;background:antiquewhite;}</style></head><body><divclass="title">天行健,君子以自强不息。</div><divclass="content">我才21岁,我好累。</div><divclass="box1"></div><divclass="box2"></div><divclass="box3_75"></div><divclass="box7_5"></div><divclass="box15"></div></body></html>这种方法的问题:只有 3 个离散断点,屏幕宽度在两个断点之间时是"跳变"而不是"连续缩放",而且断点要自己手写维护,麻烦。所以工程里一般不用它,但它最适合用来搞懂原理。
🚀 五、方法二:一行 CSS 动态适配(推荐,丝滑无断点)
不想写一堆媒体查询?用vw一行搞定连续缩放:
html{/* 100vw = 视口宽度;除以 15 份,效果和上面手动算的一模一样,但任何宽度都连续生效 */font-size:calc(100vw / 15);}/* 大屏锁死,避免 PC 上字大到爆炸 */@mediascreenand(min-width:750px){html{font-size:50px;}}calc(100vw / 15)在 750px 宽 = 50px,375px 宽 = 25px,414px 宽 = 27.6px——所有宽度自动连续缩放,不用再写断点。剩下的元素照样全用rem。
🛠️ 六、方法三:JS 动态适配(lib-flexible 同款思路)
有些老浏览器 / 特殊场景想要更可控,可以用一小段 JS(这也是阿里lib-flexible的核心思路):
(function(){functionsetRem(){vardesignWidth=750;// 设计稿宽度varparts=15;// 分成 15 份varclientWidth=document.documentElement.clientWidth;varwidth=Math.min(clientWidth,750);// 限制最大宽度,PC 端不超 750document.documentElement.style.fontSize=(width/parts)+'px';}setRem();window.addEventListener('resize',setRem);// 屏幕旋转/缩放时重算window.addEventListener('pageshow',setRem);// 从缓存页面返回时重算})();把这段放在<head>最前面(越早执行越好,避免闪屏),效果和方法二一致,但兼容性更稳、还能监听变化。
📦 七、工程化:postcss-pxtorem 自动换算
如果项目用构建工具(Vue / React / Vite),可以装postcss-pxtorem,你只管写 px,它自动帮你转 rem:
// postcss.config.jsmodule.exports={plugins:{'postcss-pxtorem':{rootValue:50,// 对应 750/15 = 50,和上面的换算一致propList:['*'],// 所有属性都转},},};注意:用了它,仍然要保留上面第六节那段setRem的 JS(用来动态设根字号),否则 rem 没有基准。
⚠️ 八、常见坑(都是原博客踩过的)
| 坑 | 说明 |
|---|---|
| 忘写 viewport | 必须加<meta name="viewport" content="width=device-width, initial-scale=1.0">,否则手机不按真实宽度渲染 |
| 媒体查询没兜底 | 只写max-width不写min-width兜底,PC 端根字号回退 16px,布局直接崩 |
| 换算注释写错 | 像原博客把0.32rem注释成 12px,实际只有 8px,纯属误导 |
| 本地图片 404 | 原博客用了./img/二维码.jpg这种相对路径,发到线上必挂。图片要传图床拿绝对地址 |
| 字体太小 | 移动端正文字号别小于 12px,否则看着费劲;rem 缩放后注意实际值 |
📚 九、参考链接
- rem适配原理 - CSDN
- rem 适配方案 - 知乎
- 详解 rem 适配布局 - 脚本之家
- vw+rem 自适应适配方案 - 知乎
- Rem 布局的原理解析 - 知乎
🧰 十、我的实战偏好:能上 UI 库就上 UI 库
讲完上面一堆手写 rem 适配,说句大实话:真正写业务项目的时候,我一般不自己手写 rem 那套。
不是因为它没用,而是——现在主流 UI 库本身就自带自适应 / 响应式能力,你站在巨人肩膀上就行,没必要重复造轮子。
| 方案 | 我现在用吗 | 说明 |
|---|---|---|
| 手写 rem(媒体查询 / vw / JS) | 偶尔 | 主要用来理解原理、调非库的原生组件 |
| Bootstrap 系列 | 以前用,现在不用了 | 经典栅格 + 响应式断点,但风格 / 体积不太合现在口味 |
| Element Plus(Vue 3) | 常用 ✅ | 组件自带响应式布局,配 Vue 项目开箱即用 |
为什么我更爱用现成 UI 库:
- 栅格系统直接给断点:比如 Element Plus 的
Row/Col用:xs :sm :md :lg :xl就能按屏幕宽度自动分栏,不用自己算750 / 15 = 50那套。 - 组件自带适配:按钮、表单、弹窗、表格这些都是库里调好的,移动端不会乱版。
- 省时间还更稳:自己手算 rem 容易踩前面列的坑(注释写错、断点没兜底、图片 404)。
但注意:rem 原理依然值得学。当你要改库组件的样式、排查"为什么这个盒子在手机上突然变小了"、或者写库没覆盖的原生模块时,懂 rem / vw 才能精准下手。
一句话总结:原理要懂,活儿能交给库就交给库。这篇教程是帮你建立底层认知,真上项目,Element Plus 这类库才是日常主力。
如果我有理解错的地方,欢迎在评论区指导修改 👏 这篇文章我会不定期修改补充,建议关注+收藏,方便回头看 ~