各位前端大佬们,今天我们来聊聊移动端开发中绕不开的话题------rem 适配。无论你是刚入行的新人,还是有一定经验的开发者,掌握 rem 适配都能让你在开发多端页面时游刃有余。本文将从原理到实战,带你彻底搞懂 rem,并附上可直接运行的示例代码。
一、为什么要做移动端适配?
现在的手机屏幕尺寸五花八门:iPhone SE(375px)、iPhone 14 Pro Max(430px)、各种安卓机型(360px、390px、412px......)。如果都用固定的 px 单位,就会出现:在大屏上元素显得太小,在小屏上又挤在一起。
我们需要一种机制,让页面元素根据屏幕宽度自动缩放,在不同设备上保持视觉比例一致。这就是移动端适配要解决的核心问题。
二、rem 是什么?
rem (root em)是一个相对单位,它相对于 HTML 根元素的 font-size。
例如:
css
css
html { font-size: 16px; }
h1 { font-size: 2rem; } /* 实际 = 32px */
p { font-size: 1rem; } /* 实际 = 16px */
如果根字体变成 20px,所有 rem 值都会等比例放大。
与 px、em 的区别
- px:绝对单位,大小固定,不随环境变化。
- em :相对单位,相对于父元素字体大小,容易嵌套混乱。
- rem:相对单位,始终相对于根元素,简单可控。
rem 非常适合用来构建可缩放的布局。
三、rem 适配的原理
核心思想:动态改变根元素的字体大小,所有使用 rem 的元素自动缩放。
公式如下:
text
scss
根字体大小 = (当前屏幕宽度 / 设计稿宽度) * 基准值
- 设计稿宽度:通常是 750px(iPhone 6/7/8 二倍图)或 375px。
- 基准值:为了方便计算,一般取 100px,这样设计稿上的 100px 在代码里就是 1rem。
举例:设计稿 750px,基准 100px。
屏幕宽 375px 时:根字体 = (375 / 750) * 100 = 50px。
此时 1rem = 50px,设计稿上一个宽 200px 的元素,在代码里写 2rem,实际渲染为 100px,完美缩放到一半。
四、实战:手写一个 rem 适配示例
我们来实现一个简单的商品卡片,让它随屏幕宽度等比缩放。
1. HTML 结构
html
xml
<!DOCTYPE html>
<html lang="zh">
<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 适配实战</title>
<style>
/* 样式稍后添加 */
</style>
</head>
<body>
<div class="card">
<img src="https://via.placeholder.com/300" alt="商品图" class="card-img">
<h3 class="card-title">复古运动鞋</h3>
<p class="card-price">¥299</p>
<button class="card-btn">立即购买</button>
</div>
<script src="rem.js"></script>
</body>
</html>
2. 动态设置根字体(rem.js)
javascript
ini
// rem.js
(function (designWidth = 750, baseSize = 100) {
function setRem() {
const width = document.documentElement.clientWidth;
// 限制最大宽度,防止在平板或电脑上过大
const maxWidth = 750;
const rem = (Math.min(width, maxWidth) / designWidth) * baseSize;
document.documentElement.style.fontSize = rem + 'px';
}
setRem();
window.addEventListener('resize', setRem);
window.addEventListener('pageshow', function (e) {
if (e.persisted) setRem();
});
})();
将这段代码保存为 rem.js 并引入页面。它会在页面加载和窗口大小变化时重新计算根字体。
3. 编写 CSS(使用 rem)
设计稿尺寸:卡片宽 340px,图片 300x300px,标题字体 28px,价格字体 32px,按钮高 70px,圆角 16px。基准 100px,所以转换为 rem:
css
css
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
background: #f5f5f5;
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
font-family: sans-serif;
}
.card {
width: 3.4rem; /* 340px / 100 */
background: white;
border-radius: 0.2rem; /* 20px / 100 */
padding: 0.2rem; /* 20px / 100 */
box-shadow: 0 0.04rem 0.1rem rgba(0,0,0,0.1);
text-align: center;
}
.card-img {
width: 100%;
height: auto;
aspect-ratio: 1/1;
border-radius: 0.16rem; /* 16px / 100 */
}
.card-title {
font-size: 0.28rem; /* 28px / 100 */
margin: 0.2rem 0 0.1rem;
}
.card-price {
font-size: 0.32rem; /* 32px / 100 */
color: #ff4400;
font-weight: bold;
margin-bottom: 0.2rem;
}
.card-btn {
height: 0.7rem; /* 70px / 100 */
width: 100%;
background: #ff4400;
color: white;
border: none;
border-radius: 0.35rem; /* 35px / 100 */
font-size: 0.28rem;
cursor: pointer;
}
4. 效果验证
在 Chrome 开发者工具中切换不同手机型号,观察卡片大小变化。你会发现卡片始终按设计稿比例缩放,完美适配各种屏幕。
五、工程化实践:自动转换 px 到 rem
手算 rem 太麻烦?我们可以使用 postcss-pxtorem 插件,在开发时直接写设计稿的 px,编译后自动转为 rem。
1. 安装依赖
bash
css
npm install postcss-pxtorem --save-dev
2. 配置 postcss.config.js
js
java
module.exports = {
plugins: {
'postcss-pxtorem': {
rootValue: 100, // 基准值,必须与 JS 中的基准一致
propList: ['*'], // 所有属性都转换
selectorBlackList: [], // 忽略的选择器
minPixelValue: 2, // 小于 2px 的不转换(保留 px)
}
}
}
3. 编写 CSS 时直接写 px
css
css
.card {
width: 340px; /* 开发时直接写 px */
background: white;
border-radius: 20px;
padding: 20px;
}
/* 编译后会自动变成 rem */
配合构建工具(Webpack、Vite),开发体验大大提升。
六、注意事项与优化
- 字体处理
有些设计希望正文字体在手机上保持合适大小,不随缩放变得过大。可以结合媒体查询对字体单独用 px 控制,或者设置一个范围。 - 1px 边框问题
在 Retina 屏上,1px 可能显示为 2px 物理像素。可以用transform: scale(0.5)或直接保留 1px(通过minPixelValue不转换)。 - 图片适配
使用img标签时,设置容器宽高比(aspect-ratio),并准备 2x、3x 图,通过srcset适配不同分辨率。 - 限制最大宽度
在平板或电脑上,页面可能过宽。可以在 JS 中限制最大宽度(如 750px),或在 CSS 中给根元素或外层容器设置max-width: 750px; margin: 0 auto;,让内容居中。 - 避免字体过大
如果根字体变得很大(例如屏幕宽 750px 时根字体 100px),页面内文字会非常大。通常我们会限制最大根字体,或者对文字单独用 vw 单位控制。
七、总结
rem 适配是移动端开发的经典方案,通过动态根字体 + rem 单位实现页面等比缩放。它的优点:
- 原理简单,兼容性好。
- 配合自动化工具,开发效率高。
- 能平滑适应各种屏幕宽度。
当然,现在也有了 vw/vh 方案,可以直接用视口单位实现类似效果。但 rem 方案仍有其不可替代的场景(如需要整体缩放字体、与第三方库配合等)。掌握 rem,你就能在移动端适配中游刃有余。
希望这篇文章对你有帮助!如果你有任何疑问,欢迎在评论区留言交流。别忘了点赞收藏,我们下期见!
附:完整示例代码
你可以将以下代码保存为一个 HTML 文件,直接运行查看效果。
html
xml
<!DOCTYPE html>
<html lang="zh">
<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 适配示例</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body {
background: #f5f5f5;
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
font-family: sans-serif;
}
.card {
width: 3.4rem;
background: white;
border-radius: 0.2rem;
padding: 0.2rem;
box-shadow: 0 0.04rem 0.1rem rgba(0,0,0,0.1);
text-align: center;
}
.card-img {
width: 100%;
height: auto;
aspect-ratio: 1/1;
border-radius: 0.16rem;
background: #ddd;
}
.card-title {
font-size: 0.28rem;
margin: 0.2rem 0 0.1rem;
}
.card-price {
font-size: 0.32rem;
color: #ff4400;
font-weight: bold;
margin-bottom: 0.2rem;
}
.card-btn {
height: 0.7rem;
width: 100%;
background: #ff4400;
color: white;
border: none;
border-radius: 0.35rem;
font-size: 0.28rem;
cursor: pointer;
}
</style>
</head>
<body>
<div class="card">
<div class="card-img"></div>
<h3 class="card-title">复古运动鞋</h3>
<p class="card-price">¥299</p>
<button class="card-btn">立即购买</button>
</div>
<script>
(function (designWidth = 750, baseSize = 100) {
function setRem() {
const width = document.documentElement.clientWidth;
const maxWidth = 750;
const rem = (Math.min(width, maxWidth) / designWidth) * baseSize;
document.documentElement.style.fontSize = rem + 'px';
}
setRem();
window.addEventListener('resize', setRem);
})();
</script>
</body>
</html>
在浏览器中打开,调整窗口大小,观察卡片如何平滑缩放。这就是 rem 适配的魅力!
