移动端Web适配方案实战总结从rem到vw的踩坑经历
先说说为啥要搞Web适配
做移动端开发,适配这个问题真的是绕不过去的大山。我之前接手一个项目,设计师给的设计稿是375px宽的,结果测试同学一测,iPhone 12显示正常,安卓各种机型都乱套了。这就是典型的适配没做好,当时真是被折磨得够呛。
现在回过头来看,Web适配主要解决的是不同设备屏幕大小差异带来的布局问题。iPhone的375px,在某些安卓机上可能就是414px或者更大,如果不处理的话,页面就会拉伸变形。
rem方案,我的首选
我一般都用rem来做适配,这个方案比较成熟稳定。核心思想就是根据根元素的font-size来计算其他元素的尺寸。比如设计稿宽度375px,我把根字体设为37.5px,那1rem就等于10px,这样换算起来就比较直观。
先看看核心代码:
function setRem() {
const docEl = document.documentElement;
const clientWidth = docEl.clientWidth;
if (clientWidth >= 750) {
docEl.style.fontSize = '100px';
} else {
docEl.style.fontSize = clientWidth / 7.5 + 'px';
}
}
setRem();
window.addEventListener('resize', setRem);
这里有个需要注意的地方:为什么要除以7.5?因为设计稿是750px(2倍图),除以7.5正好是100px,方便计算。如果设计稿是375px的,那就除以3.75。
然后CSS里就直接用rem:
.box {
width: 37.5rem; /* 对应设计稿375px */
height: 20rem; /* 对应设计稿200px */
font-size: 1.4rem; /* 对应设计稿14px */
}
vw方案也挺香
vw这个单位也越来越流行了,1vw等于视口宽度的1%。用它来做适配其实更简单,不用写JS代码。
假设设计稿375px宽,那1px就等于100vw/375=0.2667vw。我们可以用CSS预处理器来自动转换:
$design-width: 375;
@function px2vw($px) {
@return $px / $design-width * 100vw;
}
.box {
width: px2vw(375); // 100vw
height: px2vw(200); // 53.33vw
font-size: px2vw(14); // 3.73vw
}
如果你不想用预处理器,也可以直接计算。比如375px就写成100vw,200px就是53.33vw,这样换算就行。
踩坑提醒:这些地方容易出错
做过一段时间后发现几个特别容易踩坑的地方:
- border 1px的问题:在高清屏上,1px可能看起来很粗。可以用transform: scale(0.5)来处理
- 图片适配:记得给img设置max-width: 100%,避免溢出容器
- 字体不要用rem:字体用px或em更好,用rem在不同设备上可能会出现字体过小或过大的问题
特别是border 1px这个问题,我之前调试了好久才发现原因。现在的做法是:
.border-1px {
position: relative;
}
.border-1px::after {
content: '';
position: absolute;
bottom: 0;
left: 0;
width: 100%;
height: 1px;
background: #ddd;
transform: scaleY(0.5);
transform-origin: 0 0;
}
混合方案,取长补短
有些场景单纯用rem或vw都不太合适,我会结合使用。比如大屏展示类的页面,用vw做整体布局,用rem控制细节。
还有一种情况,就是需要适配刘海屏、挖孔屏这种异形屏。这时候就需要配合CSS env()函数:
.safe-area {
padding-top: env(safe-area-inset-top);
padding-bottom: env(safe-area-inset-bottom);
}
这个函数能获取到安全区域的边距,避免内容被刘海遮挡。
工具辅助,解放双手
手动换算px到rem或vw太麻烦了,我一般会用PostCSS插件来自动转换。
安装postcss-pxtorem:
npm install postcss-pxtorem --save-dev
配置webpack:
module.exports = {
plugins: [
require('postcss-pxtorem')({
rootValue: 37.5, // 设计稿宽度/10
propList: ['*'],
selectorBlackList: ['.no-rem']
})
]
}
这样写CSS的时候直接用px,构建时会自动转成rem。需要注意的是,rootValue的值要跟JS中设置的根字体大小保持一致。
性能优化小技巧
适配方案虽然解决了兼容性问题,但也带来了一些性能考虑。特别是rem方案,频繁的resize监听可能影响性能。
优化方法:
- 防抖处理resize事件,不要让setRem频繁执行
- 对于不需要动态调整的元素,可以用固定的rem值
- 考虑用CSS媒体查询处理一些固定断点的情况
防抖版本的代码:
let timeoutId;
function debounceSetRem() {
clearTimeout(timeoutId);
timeoutId = setTimeout(setRem, 100);
}
window.addEventListener('resize', debounceSetRem);
最后的小结
Web适配这东西说复杂也复杂,说简单也简单。关键是要根据项目需求选择合适的方案。我现在一般推荐rem+postcss的组合,稳定可靠,维护成本也不高。
当然,这几种方案都有各自适用的场景,vw适合简单的响应式布局,rem适合精细化的像素级还原。最重要的是要考虑团队的技术栈和维护成本。
以上是我踩坑后的总结,希望对你有帮助。这个技巧的拓展用法还有很多,后续会继续分享这类博客。

暂无评论