多端适配实战总结从设计到实现的完整解决方案
多端适配的坑,真是防不胜防
最近在做一个移动端项目的时候,被多端适配折腾得够呛。本来觉得用 viewport 和 rem 就能搞定一切,结果上线后发现各种奇怪问题:字体大小不对、按钮点不到、布局错乱……简直怀疑人生。最后花了几天时间才找到一套靠谱的解决方案,这里记录一下踩过的坑和解决过程。
问题是从一个简单的点击开始的
事情是这样的,我在开发一个商城页面,设计稿宽度是 750px,按惯例用 rem 做单位,1rem = 100px。本地调试时看起来没啥问题,结果测试同学反馈说,在某些安卓机上按钮特别小,几乎点不到。
当时我就懵了,明明设置了固定宽高啊!后来一查才发现,原来不同设备的默认字体大小设置不一样,导致 rem 的计算基准出了偏差。更糟的是,有些用户还会手动调整系统字体大小,这就让问题变得更复杂。
先试了个“简单粗暴”的方法
为了解决这个问题,我一开始用了个很土的办法:meta viewport 强制缩放。代码长这样:
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
但很快就发现问题没那么简单。虽然视觉效果统一了,但用户体验反而变差了——用户不能放大缩小页面,操作起来很别扭。
折腾了半天发现,这种强制手段根本治标不治本,而且很多现代浏览器已经对 user-scalable=no 进行限制,干脆弃用了这个方案。
三种方案对比,我选了最灵活的
接着我又尝试了几种主流的适配方案:
- 纯媒体查询(Media Query):通过 CSS 针对不同屏幕写样式,优点是简单直接,缺点是维护成本太高,尤其是设计稿频繁变动时。
- 百分比布局:利用相对单位实现弹性布局,适合一些简单的场景,但对于复杂的交互组件还是不够精细。
- 动态 rem + JavaScript 动态调整:最终选择了这套方案,因为它既灵活又可控。
核心代码就这几行
下面是完整的动态 rem 实现逻辑:
(function () {
function setRemUnit() {
const baseWidth = 750; // 设计稿宽度
const htmlElement = document.documentElement;
let clientWidth = htmlElement.clientWidth || 375; // 默认值防止极端情况
// 限制最小宽度,避免过窄屏幕导致字体太小
if (clientWidth < 320) {
clientWidth = 320;
}
// 计算根元素字体大小
htmlElement.style.fontSize = ${(clientWidth / baseWidth) * 100}px;
}
// 初始化设置
setRemUnit();
// 监听窗口变化
window.addEventListener('resize', setRemUnit);
})();
这段代码的核心思想就是根据当前屏幕宽度动态计算根元素的字体大小,从而让所有基于 rem 的尺寸自适应。
举个例子,如果设计稿中某个按钮宽高是 200px,那么我们只需要写成 width: 2rem; height: 2rem;,剩下的交给脚本来处理。
踩坑提醒:这三点一定注意
虽然这套方案挺好用,但也踩了不少坑,总结下来有三点需要注意:
- 不要忽略极限情况:比如超小屏或超大屏设备,如果没有设置上下限,可能会出现字体过小或过大。
- 图片资源需要单独处理:对于高清图和图标,最好使用 SVG 或者 2x 图片,并配合
background-size等属性进行优化。 - 第三方库兼容性:如果你引入了像 Swiper、ECharts 等第三方插件,记得检查它们是否依赖固定的像素值,可能需要额外配置。
还有个小问题没完全解决
目前这套方案基本满足需求,但还是有个小问题:在横竖屏切换时,偶尔会出现短暂的布局错乱。原因可能是 resize 事件触发时机稍晚,导致重新计算前有一帧空白。
我的临时解决办法是加了个防抖函数:
let timer;
window.addEventListener('resize', () => {
clearTimeout(timer);
timer = setTimeout(setRemUnit, 100);
});
虽然不是最优解,但至少改善了大部分情况,凑合着用吧。
以上是我踩坑后的总结
总的来说,动态 rem 是一个多端适配的好选择,尤其是在需要兼顾多种分辨率的情况下。不过每种方案都有局限性,大家还是要结合实际业务场景来决定。
如果你有更好的适配方案或者改进意见,欢迎评论区交流!后续我也会继续分享类似的实战经验,希望对你有所帮助。
