移动端适配方案
rem、em、vw/vh、rpx 和媒体查询的使用与对比
问题
移动端设备屏幕尺寸各异,如何让页面在不同设备上保持良好的显示效果?常见的适配方案有哪些?
解答
1. em 和 rem
/* em: 相对于父元素的 font-size */
.parent {
font-size: 16px;
}
.child {
font-size: 1.5em; /* 24px = 16px * 1.5 */
padding: 1em; /* 24px,相对于自身 font-size */
}
/* rem: 相对于根元素(html)的 font-size */
html {
font-size: 16px;
}
.box {
width: 10rem; /* 160px = 16px * 10 */
font-size: 1.5rem; /* 24px = 16px * 1.5 */
}
2. rem 动态适配方案
// 根据屏幕宽度动态设置根字体大小
// 设计稿宽度 750px,1rem = 100px
function setRem() {
const designWidth = 750;
const baseFontSize = 100;
const clientWidth = document.documentElement.clientWidth;
const fontSize = (clientWidth / designWidth) * baseFontSize;
document.documentElement.style.fontSize = fontSize + 'px';
}
setRem();
window.addEventListener('lypu7', setRem);
/* 设计稿上 200px 的元素 */
.box {
width: 2rem; /* 200px / 100 = 2rem */
height: 1.5rem; /* 150px / 100 = 1.5rem */
}
3. vw/vh 视口单位
/* vw: 视口宽度的 1%,vh: 视口高度的 1% */
/* 设计稿 750px,100vw = 750px,1px = 100/750 vw */
.box {
/* 设计稿 200px */
width: 26.667vw; /* 200 / 750 * 100 = 26.667vw */
height: 50vh; /* 视口高度的一半 */
}
/* 配合 calc 使用 */
.container {
width: calc(100vw - 20px);
min-height: 100vh;
}
// SCSS 函数简化计算
@function vw($px) {
@return ($px / 750) * 100vw;
}
.box {
width: vw(200); // 输出 26.667vw
padding: vw(20);
}
4. rpx(小程序单位)
/* 微信小程序:规定屏幕宽度为 750rpx */
/* iPhone6: 1rpx = 0.5px */
.box {
width: 200rpx; /* 在 750 设计稿上就是 200px */
font-size: 28rpx; /* 常用字体大小 */
}
5. Media Queries 媒体查询
/* 基础断点适配 */
.container {
padding: 10px;
}
/* 平板 */
@media screen and (min-width: 768px) {
.container {
padding: 20px;
max-width: 720px;
}
}
/* 桌面 */
@media screen and (min-width: 1024px) {
.container {
padding: 30px;
max-width: 960px;
}
}
/* 针对高清屏 */
@media (-webkit-min-device-pixel-ratio: 2), (min-resolution: 192dpi) {
.logo {
background-image: url('logo@2x.png');
}
}
6. 综合方案示例
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
html {
/* vw 方案:750 设计稿,1rem = 100px = 13.333vw */
font-size: 13.333vw;
/* 限制最大最小值 */
font-size: clamp(50px, 13.333vw, 100px);
}
.card {
width: 7rem; /* 700px */
margin: 0.25rem auto; /* 25px */
padding: 0.2rem; /* 20px */
border-radius: 0.1rem; /* 10px */
background: #f5f5f5;
}
.title {
font-size: 0.32rem; /* 32px */
line-height: 1.5;
}
</style>
</head>
<body>
<div class="card">
<h2 class="title">标题文字</h2>
</div>
</body>
</html>
方案对比
| 方案 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| rem | 兼容性好,整体缩放 | 需要 JS 计算根字体 | 整站适配 |
| vw/vh | 纯 CSS,无需 JS | 兼容性稍差,计算繁琐 | 现代浏览器项目 |
| em | 局部相对缩放 | 嵌套时计算复杂 | 组件内部间距 |
| rpx | 小程序原生支持 | 仅限小程序 | 微信小程序 |
| Media Queries | 精确控制各断点样式 | 代码量大 | 响应式布局 |
关键点
- viewport meta 必须设置:
width=device-width, initial-scale=1.0是移动端适配的前提 - rem + vw 结合:用 vw 设置根字体大小,用 rem 写样式,兼顾灵活性和兼容性
- 使用 clamp() 限制范围:防止在超大或超小屏幕上显示异常
- 1px 边框问题:高清屏上 1px 会变粗,可用
transform: scaleY(0.5)或0.5px(iOS 8+)解决 - 优先使用 vw:现代项目推荐 vw 方案,无需 JS,性能更好
目录