主题
移动端适配与 rem(一)
本页对应 移动端适配与 rem,共 7 段视频,约 52 分钟。
学习目标
- 能用自己的话解释移动适配的含义,并举例说明同一元素在不同移动设备上显示尺寸不同的原因。
- 能使用 Chrome 开发者工具打开设备模拟器,切换 iPhone 5、iPhone 6/7/8、iPhone 6/7/8 Plus,完成页面刷新并调整调试面板位置。
- 能区分物理分辨率与逻辑分辨率,准确说出 iPhone 5、iPhone 6/7/8、iPhone 6/7/8 Plus 的逻辑分辨率。
- 能解释移动端网页默认按 980px 显示导致页面缩小的原因,并为页面添加正确的 viewport meta 标签。
- 能识别二倍图设计稿,在 PSD 或网页设计稿中将缩放/像素密度校准为 2 倍后再量取尺寸。
- 能说明 rem 作为移动端适配方案的基本原理,即长度单位相对于根元素字体大小进行计算。
知识点
谷歌模拟器

为什么需要: 移动端页面最终要在手机、平板上看,但写代码时不可能一直插数据线用真机测试,所以先用谷歌浏览器模拟移动设备,方便查看页面效果。
怎么想: 模拟器只是把浏览器的“可视区域”切成手机尺寸;它不改变代码,改变的是查看环境。转写里反复强调:切换设备后页面要刷新,否则你看到的还可能像 PC 页面。
怎么做: 在页面空白处右键 →“检查”打开控制台 → 点控制台左上角的设备切换图标 → 选择 iPhone 5、iPhone 6/7/8、iPhone 6/7/8 Plus 等设备。建议把调试栏放到左右两侧,避免挤占设备宽度;缩放比例保持 100%,不要用 Ctrl+滚轮 缩放浏览器。找不到设备时,在设备下拉最底部点 Edit 勾选需要的机型;还可以切换横屏/竖屏。
易错点: 切换设备后忘记刷新;调试栏放在下方把设备“挤小”;用浏览器缩放代替设备缩放,导致尺寸判断不准;把模拟器当成真机,忽略不同设备宽度不同。
屏幕分辨率

为什么需要: 不同手机屏幕大小不同,同一个元素在不同设备上显示大小也不同,这就是移动适配要解决的问题。写页面前必须知道以哪个“分辨率”为参照。
怎么想: 分辨率分两类:物理分辨率是硬件分辨率,出厂就固定;逻辑分辨率是软件/驱动设置后的分辨率。转写里用电脑举例:物理 1920×1080,在 100% 缩放下逻辑分辨率也是 1920×1080,看不出区别;调到 125% 后,逻辑宽度约为 1920 ÷ 1.25 = 1536,页面大小就跟着逻辑分辨率变了。结论是:制作网页参考逻辑分辨率。
怎么做: 记住常用移动设备逻辑分辨率:iPhone 5 为 320×568;iPhone 6/7/8 为 375×667;iPhone 6/7/8 Plus 为 414×736。最需要先记住 iPhone 6/7/8 的宽度 375,因为设计师常以它为设计稿基准。
易错点: 把物理分辨率和逻辑分辨率混用;记成“页面按物理分辨率写”;只记高度不记宽度。实际沟通中常以宽度判断设备适配基准。
视口
为什么需要: 视口是显示 HTML 网页的区域,用来约束 HTML 的尺寸。转写里演示:不加视口标签时,移动浏览器默认按约 980px 的宽度布局网页,再塞进 375px 左右的设备里,页面只能被缩小,字很小、没法看。
怎么想: 要让“视口宽度”和“设备宽度”一致,比例设为 1:1,这样页面才能按设备宽度正常显示。
怎么做: 在 head 中加入视口标签:
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<!– 视口标签 -->
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
</body>
</html>其中 width=device-width 表示视口宽度等于设备宽度;initial-scale=1.0 表示缩放 1 倍、不缩放。实际开发中这句话通常由编辑器骨架自动生成,但要知道它的作用。
易错点: 漏写视口标签导致页面被整体缩小;把 initial-scale 写成其他值造成缩放异常;以为加了视口标签就完成所有适配,它只解决视口与设备宽度对齐问题。
二倍图

为什么需要: 设计稿如果只按 375px 做一倍图,图片放到更大或更高分辨率的屏幕下容易被放大而模糊失真。二倍图就是设计稿中元素尺寸按设备尺寸的 2 倍来做,防止图片在高分辨率屏幕下模糊失真。
怎么想: 以 iPhone 6/7/8 为例,设备逻辑宽度 375,二倍设计稿宽度通常是 750。你在设计稿上量到 750,不能直接写成 CSS 的 750px,而要按二倍关系换算成 375px。转写中强调:看到设计稿量出来是设备宽度的两倍,第一反应就是“二倍图”。
怎么做: 使用设计稿前先校准。网页版设计稿可在设置里把像素密度改成 2x 再量;PSD 设计稿也要按二倍图关系校准/换算后再量,不能拿设计稿标注值直接当 CSS 像素。写页面时图片资源可按二倍图准备,CSS 尺寸按逻辑尺寸写。
易错点: 直接量 750 就写 750;把二倍图理解成“页面所有 CSS 都乘 2”;只换图片不换尺寸;不校准设计稿就开始量。
适配方案
为什么需要: 移动设备宽度不同,同一个元素在不同设备下要有合适显示,不能只写死一套固定像素。转写里明确:移动适配就是不同设备下同一元素有不同大小显示。
怎么想: 适配分两条线:宽度适配解决“宽度自适应”,如百分比布局、Flex 布局;等比适配解决“宽高等比缩放”,如 rem、vw。今天先建立框架,后面再细讲 rem 和 vw。
怎么做: 做横向排列、宽度分配时优先考虑百分比/Flex;需要整体按屏幕比例缩放时使用 rem/vw。不要把“宽度自适应”和“等比缩放”混为一谈。
易错点: 全用固定 px 导致小屏溢出、大屏留白;以为 Flex 能解决所有等比缩放;忘记二倍图换算;切换设备后不刷新就判断适配效果。
从移动适配理解 rem
为什么需要:手机、平板等设备宽度不同,同一个元素如果写死 px,在不同设备上显示大小就会不一样。转写稿里把这件事说得很直接:移动适配就是同一个元素在不同设备下有不同的大小显示。
怎么想:既然设备宽度会变,就不能只依赖固定像素,要让尺寸跟着视口变化。rem 就是为此服务的相对单位。
怎么做:先记住结论:rem 是相对单位,相对于 HTML 标签的字号计算结果,1rem = 1个HTML字号大小。
易错点:rem 不是相对父元素字号,而是相对根节点 html 的字号;不要和 em 混淆。
rem 单位的基本含义
为什么需要:移动端页面要在不同宽度下保持比例,固定 px 无法自动缩放。
怎么想:只要 HTML 根字号会随视口变化,那么用 rem 写的元素尺寸也会随之变化。
怎么做:把设计稿中的 px 换算成 rem,页面中写 rem。例如根字号变化时,2rem 的实际大小也会变化。
易错点:1rem 永远等于当前 html 的字号,不是固定 16px;如果手动改了 html 字号,所有 rem 尺寸都会跟着变。
媒体查询:按视口宽度写差异化样式
为什么需要:不同视口宽度下,可能需要执行不同的 CSS 样式。媒体查询能够检测视口的宽度,然后编写差异化的 CSS 样式。
怎么想:把“某个条件成立”作为开关,条件成立时才执行对应 CSS。
怎么做:例如当视口宽度为 320px 时,把 html 背景改成绿色:
css
@media (width:320px) {
html {
background-color: green;
}
}
易错点:媒体查询检测的是视口宽度,不要理解成设备物理分辨率;在谷歌模拟器里切换设备后要刷新页面再看效果;条件不成立时样式不会执行。
rem 布局:把视口等分成 10 份
为什么需要:如果每个元素都单独算比例,开发会很麻烦,需要一套统一的基准。
怎么想:目前 rem 布局方案中,将网页等分成 10 份,HTML 标签的字号为视口宽度的 1/10。这样 1rem 就代表视口宽度的十分之一。
怎么做:先确定参考设备视口宽度,再算出基准根字号:基准根字号 = 视口宽度 / 10。页面元素按这个基准换算成 rem。
易错点:根字号不是随便写一个固定值,而是跟视口宽度挂钩;不要把“网页等分成 10 份”理解成每个元素固定占一份。

flexible.js:自动设置根字号
为什么需要:不同视口宽度下都要重新计算 html 的 font-size,手写容易漏、容易错。
怎么想:flexible.js 是手淘开发出的一个用来适配移动端的 js 库,核心原理就是根据不同的视口宽度给网页中 html 根节点设置不同的 font-size。
怎么做:在页面底部引入:
html
<body>
......
<script src="./js/flexible.js"></script>
</body>易错点:引入位置要按笔记放在 body 末尾;切换模拟器设备后要刷新页面观察根字号变化;如果自己又手动写死 html 字号,可能和 flexible.js 的设置冲突。
rem 移动适配的计算步骤
为什么需要:设计稿给的是 px,页面要写 rem,必须有统一换算方法。
怎么想:先确定基准根字号,再把 px 数值除以基准根字号。
怎么做:
- 确定基准根字号:查看设计稿宽度 → 确定参考设备宽度(视口宽度)→ 确定基准根字号(
1/10视口宽度)。 - 换算 rem 单位尺寸:rem单位的尺寸 = px单位数值 / 基准根字号。
例如参考视口宽375px,基准根字号是37.5px;设计稿某元素75px,则75 / 37.5 = 2rem。
易错点:除的是“基准根字号”,不是设计稿宽度;设计稿宽度和参考视口宽度要对应;换算后单位写rem,不要又写回px。调试时可在谷歌模拟器切换不同设备并刷新,观察html字号和元素尺寸是否按比例变化。
课件图示




代码示例
代码一:移动 Web 基础页面骨架(视口标签 + Flex 宽度适配)
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<!-- 视口标签:width=device-width 视口宽度=设备宽度,initial-scale=1.0 缩放1倍(不缩放) -->
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
* { margin: 0; padding: 0; }
/* 宽度适配:Flex 布局,宽度自适应 */
.nav {
display: flex;
}
.nav div {
flex: 1;
height: 44px;
line-height: 44px;
text-align: center;
background-color: pink;
border-right: 1px solid #fff;
}
</style>
</head>
<body>
<div class="nav">
<div>首页</div>
<div>分类</div>
<div>我的</div>
</div>
</body>
</html>要点解释:
name="viewport"中的viewport就是视口,作用是约束 HTML 的尺寸;width=device-width让视口宽度等于设备宽度,initial-scale=1.0表示不缩放,两者配合让“网页宽度 = 逻辑分辨率宽度”,比例为 1:1。- 如果不加视口标签,移动端网页默认宽度是 980,用 375 宽的设备去看,只能把整个页面缩小后塞进去,字小到看不清,所以这一行是移动端页面的前提。
- 制作网页参考的是逻辑分辨率(不是物理分辨率),记住 iPhone 6/7/8 的逻辑分辨率宽是 375。
- 易错点:切换谷歌模拟器设备后必须刷新页面才生效;调试栏建议放到左侧或右侧,并且缩放比例保持 100%,否则设备尺寸会被挤小、测出来的数值不准。
- 易错点:这段只解决了“宽度自适应”,元素高度是写死的 44px,并没有等比缩放,所以后面还要用 rem、vw 来做等比适配。
代码二:媒体查询 + rem 布局(网页等分 10 份)
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>媒体查询 + rem</title>
<style>
* { margin: 0; padding: 0; }
/* 媒体查询:检测视口宽度,条件成立才执行里面的 CSS */
/* rem 布局方案:网页等分成 10 份,html 字号 = 视口宽度 / 10 */
@media (width: 320px) {
html { font-size: 32px; } /* 320 / 10 */
}
@media (width: 375px) {
html { font-size: 37.5px; } /* 375 / 10 */
}
@media (width: 414px) {
html { font-size: 41.4px; } /* 414 / 10 */
}
.box {
/* rem 单位的尺寸 = px单位数值 / 基准根字号 */
/* 375 下设计稿量得 75px → 75 / 37.5 = 2rem */
width: 2rem;
height: 2rem;
background-color: pink;
}
.box2 {
width: 4rem; /* 375 下 = 150px,320 下 = 128px,等比缩放 */
height: 1rem;
background-color: skyblue;
}
</style>
</head>
<body>
<div class="box"></div>
<div class="box2"></div>
</body>
</html>要点解释:
rem是相对单位,1rem = 1 个 HTML 标签的字号大小,所以改变html的font-size就等于改变整个页面的度量基准。- 媒体查询的写法是
@media (width: 320px) { ... },注意是width加冒号,不是max-width,这里匹配的是视口宽度等于该值。 - 换算公式必须记牢:rem 单位的尺寸 = px 单位数值 ÷ 基准根字号;基准根字号 = 设计稿参考设备宽度 ÷ 10。
- 易错点:设计稿通常是二倍图(如 iPhone 6/7/8 的设计稿宽度是 750),量出来的 px 要先 ÷2 还原成 375 下的尺寸,再 ÷37.5 换算成 rem;直接拿 750 的数值算,尺寸会大一倍。
- 易错点:用媒体查询做 rem 适配,只能覆盖到列出来的这几个宽度,其他宽度下
html没有字号,rem 会失效,所以才有了下面的 flexible.js。
代码三:flexible.js 原理演示(按视口宽度动态设置根字号)
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>flexible.js 适配</title>
<style>
* { margin: 0; padding: 0; }
.box {
/* 375 设计稿量得 75px,基准根字号 37.5 → 75 / 37.5 = 2rem */
width: 2rem;
height: 2rem;
background-color: pink;
}
.box2 {
width: 4rem;
height: 1rem;
background-color: skyblue;
}
</style>
</head>
<body>
<div class="box"></div>
<div class="box2"></div>
<!-- 实际项目中直接引入即可,放在 body 最后 -->
<!-- <script src="./js/flexible.js"></script> -->
<script>
// 下面这段为手写简化版,演示 flexible.js 的核心原理:
// 根据不同的视口宽度给网页中 html 根节点设置不同的 font-size
(function () {
function setRemUnit() {
var html = document.documentElement;
// 网页等分成 10 份,根字号 = 视口宽度 / 10
html.style.fontSize = html.clientWidth / 10 + 'px';
}
setRemUnit(); // 页面打开时先执行一次
window.addEventListener('resize', setRemUnit); // 视口变化时重新计算
})();
</script>
</body>
</html>要点解释:
- flexible.js 是手淘开发的移动端适配 js 库,核心原理就是按视口宽度给 html 根节点设置 font-size,从而省掉一大堆媒体查询。
- 脚本放在
body最后(或用src引入./js/flexible.js),保证 DOM 已经解析到,同时尽早设置根字号,避免页面先按默认字号渲染再跳变。 - 写了
fontSize之后,CSS 里所有尺寸统一用 rem 写,页面就会在不同设备上等比缩放。 - 易错点:
document.documentElement拿的才是html根节点,写成document.body则 rem 不生效。 - 易错点:换算 rem 之前一定要先确认基准根字号(1/10 视口宽度),并且先确认设计稿是不是二倍图;这两个前提没搞清,后面所有 rem 数值都是错的。
常见错误
1. 切到模拟器后页面“没反应”
- 现象:点完设备图标,页面还是 PC 版的样子,样式或布局毫无变化。
- 原因:切换设备只是换了渲染视口,当前文档没有重新加载,浏览器仍沿用旧的布局结果。
- 修法:切换设备后强制刷新(F5 / ⌘R);同时把缩放比例调回 100%(别用 Ctrl+滚轮缩放页面),调试面板停靠到左右两侧,避免挤压设备宽度。
2. 移动端页面被“缩成一小坨”,字小到看不清
- 现象:手机上打开自己的页面,整页像缩略图,写多大字号都没用。
- 原因:
<meta name="viewport">漏写、写错、被注释掉,或只写了width没写initial-scale,浏览器按默认 980px 宽渲染再整体缩放。 - 修法:在
<head>里补齐width=device-width, initial-scale=1.0;检查引号是英文引号、标签没被<!-- -->包住、没被误写进<style>里。
3. 照着设计稿量,页面整体“放大一倍”
- 现象:量出卡片宽 750,写进 CSS 后元素撑满屏幕,跟设计稿完全对不上。
- 原因:设计稿是二倍图,直接在 1x 像素密度下测量,量到的是物理像素而非逻辑像素。
- 修法:PSD 用“图像 → 图像大小”改 50%,网页设计稿在渲染面板把像素密度设为 2x,校准后再量;量出的 px 再按 rem 规则换算。
4. rem 换算结果不对,元素大小忽大忽小
- 现象:同样的
2rem,在不同页面/不同同学手里大小不同,或整体偏大偏小一倍。 - 原因:基准根字号取错——拿了物理分辨率、拿了二倍图宽度、或团队里有人用 750 有人用 375 作基准。
- 修法:先固定基准:基准根字号 = 设计稿(逻辑)宽度 ÷ 10;
rem = px ÷ 基准根字号;全组统一用同一套基准,别中途换。
5. 媒体查询写了一堆断点,中间尺寸还是错位
- 现象:320、375、414 都对,一到 360、390 就布局错乱。
- 原因:用
width: 375px这种精确匹配写断点,只在该宽度成立,其余宽度全部落空。 - 修法:要么改用
min-width/max-width写区间,要么直接交给 flexible.js 动态设html字号做连续适配,媒体查询只负责差异化样式(如某些区块隐藏)。
6. flexible.js 引入了却没生效
- 现象:
html的 font-size 始终是默认值,rem 布局整体崩。 - 原因:script 路径写错、被放在
<head>里 DOM 未就绪,或自己在 CSS 里写死了html { font-size: ... }把它覆盖了。 - 修法:
<script src="./js/flexible.js">放在</body>前并核对路径;CSS 里不要再给html写固定字号。
7. 宽度自适应了,高度却溢出
- 现象:百分比 / Flex 布局下横向刚好,纵向内容被挤出去或留大片空白。
- 原因:只处理了宽度维度,高度仍写死 px,未随视口等比变化。
- 修法:需要宽高等比缩放的区块改用 rem / vw 描述尺寸;纯横向自适应才用百分比 / Flex,两种方案别在同一维度混用。
练习
练习 1|模拟器基本功 用谷歌模拟器分别切到 iPhone 5、iPhone 6/7/8、iPhone 6/7/8 Plus,打开京东移动站,用元素选择器量同一个按钮的宽度,记录三组数据,并用一句话解释差异来源。要求:切换后刷新、缩放保持 100%、面板停靠右侧。
练习 2|视口对照实验 新建一个含标题和一张图片的页面,做三组对照:① 注释掉 viewport 标签;② 恢复 initial-scale=1.0;③ 改成 initial-scale=2.0。截图记录三种表现,并说明为什么第一种“必然看不清”。
练习 3|二倍图测量与换算 打开课程素材里的游乐园设计稿,先在 2x 像素密度下校准,再量出页面头部高度、某个卡片宽高和一个标题字号,以 375 逻辑宽为基准(基准根字号 37.5)换算成 rem,写出对应 CSS。
练习 4|手写最小适配 不使用 flexible.js,只用媒体查询 + 手算,让 750 设计稿里宽 100px 的元素在 320 / 375 / 414 三种视口下都保持等比(约为视口宽的 13.3%)。写出你的 html 字号设定和元素 CSS。
练习 5|flexible.js 验证 引入 flexible.js 完成游乐园页面头部,在 320 / 375 / 414 / 横屏四种状态下检查元素是否等比缩放;同时回答:如果把 html { font-size: 20px } 写进 CSS,会出现什么后果。
原视频对照
| # | 视频 | 时长 |
|---|---|---|
| 1 | 课程介绍 | 06:10 |
| 2 | 谷歌模拟器 | 09:13 |
| 3 | 分辨率 | 09:27 |
| 4 | 分辨率 | 04:26 |
| 5 | 分辨率 | 06:17 |
| 6 | 视口 | 08:35 |
| 7 | 二倍图 | 08:18 |
小结
- 做移动端只认逻辑分辨率:iPhone 6/7/8 = 375×667 必须张口就来,320 与 414 也要记住。
- viewport meta 是移动页面的“入场券”,缺了它一切适配都是白做,默认 980 宽渲染必然错乱。
- 模拟器的正确姿势是:切设备 → 刷新 → 缩放 100% → 面板靠边;这三步不做,后面所有调试结论都不可信。
- 设计稿一律是二倍图,量之前先切 2x,量完的数值代表逻辑像素,不要直接当 CSS 值用。
- rem 只有三步:定基准根字号(视口宽 ÷ 10)→ px ÷ 基准 → 写成 rem;混乱的根源永远是基准没统一。
- 分工要清楚:宽度自适应交给百分比 / Flex,等比缩放交给 rem / vw,不要在同一个维度上两套方案混用。
- flexible.js 负责动态改
html字号,媒体查询负责差异化样式;别用width: 375px这种精确断点去硬凑设备。 - 二倍图解决的是高分屏清晰度问题,不改变元素的逻辑尺寸——元素该多大还是多大,只是素材更清晰。