干前端这些年,移动端适配几乎是每个项目都绕不过去的坎。从最初的viewport缩放,到rem方案,再到vw/vh布局,各种方案层出不穷,面试还总爱问,稍不留神就容易踩坑。这篇东西,我不打算讲什么大而全的理论,就结合这几年真金白银换来的经验,把移动端适配这件事从头到尾捋一遍。从最基础的原理、到现在主流的几套玩法、再到那些通常文档里不写但坑到无数人的细节,全给你盘出来。不管你是刚入行的新人,还是被各种奇奇怪怪bug折磨的“老兵”,看完这篇,不敢说你就无敌了,但至少能让你的页面在各种屏幕上站稳脚跟,少走点弯路。
这篇文章里,我会把“什么是适配”、“为什么要适配”这类基础逻辑先讲透,因为很多人其实栽就栽在基础概念没吃透。紧接着会拆解四大主流实战方案,包括它们的核心代码、换算逻辑、优缺点和适用场景。再往后,是各种“疑难杂症”的排查实录,像是1px变粗、安全区顶底、输入框被键盘挡住、横竖屏切换这些让人想摔手机的破事,我都会给出亲测有效的解决方案。最后,再聊聊移动端性能优化和未来方案的趋势,让整个知识体系更完整。
1. 移动端适配的本质:先弄懂几个要命的概念
1.1 我们到底在适配什么?
说白了,适配要解决的核心问题只有一个:同一个设计稿,在不同宽度、不同分辨率、不同像素密度的屏幕上,呈现出来的视觉比例和交互体验要一致。
很多新人上来就写CSS,觉得px单位是万能的。但你看啊,一台iPhone SE的逻辑宽度是375px,一台安卓旗舰的逻辑宽度可能是412px,甚至现在折叠屏内屏宽度到了673px。你要是用固定宽度写死,比如写个width: 375px的容器,在iPhone SE上是满屏,放到折叠屏上右边就空出一大截,那像话吗?
所以必须要理解一个核心概念:屏幕上有个东西叫物理像素(设备屏幕实际拥有的像素点),还有个东西叫逻辑像素(CSS像素,我们写代码用的单位)。它们之间的比例关系就是设备像素比(devicePixelRatio,简称dpr)。
iPhone 6/7/8的dpr是2,也就是说一个CSS像素其实是2x2个物理像素。iPhone 13 Pro Max的dpr是3,一个CSS像素是3x3个物理像素。这个概念一弄懂,后面很多东西就通了。比如后面要说的“1px物理像素线”,本质就是要在dpr=2或者=3的屏幕上,把1px的CSS像素线渲染成真正的“一条物理像素亮线”,而不是占了2个或3个物理像素的粗线。
1.2 为什么移动端要比PC端复杂一万倍?
PC端你主要就对付那几种主流分辨率,1366x768、1920x1080,顶多再算上2K屏和Mac的Retina屏。而且PC浏览器默认就可以缩放页面,用户自己会去调。
移动端不一样,残酷得很。iPhone这边,从老的320px、375px,到现在的390px、393px、430px,都没怎么乱来,比较规范。但安卓阵营那就是亚马逊丛林,什么720x1280、1080x1920、1440x3200,还有各种折叠屏内屏外屏不同尺寸,更别提国产五花八门的全面屏刘海、挖孔、灵动岛。你永远不知道用户拿的是什么设备。
再加上移动端还要考虑横竖屏切换、软键盘弹起、系统字体大小设置、底部安全区(iPhone的Home Indicator那条小黑条)等等一系列幺蛾子。所以,移动端适配没有一个“一招鲜吃遍天”的银弹,正确的做法是多种方案互相配合。这个思想你得先建立起来。
2. 四大主流适配方案实操拆解
2.1 基础但管用的viewport怎么设置才不坑?
viewportmeta标签是移动端适配的基石,几乎所有方案都要依赖它。如果这个写不对,后面全白搭。
标准写法如下:
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">这个标签告诉浏览器:页面的宽度请按照设备的宽度来,初始缩放比例为1,不允许用户手动缩放。width=device-width这句话很关键,它让布局视口的宽度等于设备逻辑像素宽度,这样我们的rem、vw这些相对单位才有正确的参照基准。
但这里有个大坑:user-scalable=no以及maximum-scale=1.0在iOS 10以上的Safari里其实是失效的。苹果为了“无障碍访问”(Accessibility),强制允许用户通过辅助功能放大页面。这就意味着,即便你禁了手动缩放,用户在系统设置里开了“辅助功能-显示与文字大小-放大文字”或者“缩放”的话,你的页面照样会被放大,布局照样乱给你看。尤其是用了vw或者rem这种相对单位的时候,字体可能被系统级缩放,导致样式错乱。
所以,关于viewport的知识点要更新一下:
user-scalable=no部分设备会失效,不要指望它——这在无障碍适配(热词里的“无障碍适配”)中是个重要考点。- 为了照顾视障用户和系统字体设置,排版上要预留一定的弹性空间。
- 如果你做的是一些H5活动页,UI非常固定,可以考虑用
maximum-scale=1.0来尽量控制,但别对安卓机报太大希望。
我还见过一种骚操作,就是为了适配老旧安卓的“双击缩放”问题,给viewport加user-scalable=no。结果用户没法缩放了,但页面上的横向滚动却因为某些元素超出宽度触发,体验更差。所以归根结底,先把布局本身做好,才是王道。
2.2 传统rem方案:从字体换算到整体布局
rem(Root Em)是相对<html>根元素的字体大小来计算的。也就是说,如果根元素的font-size是100px,那么1rem就等于100px。这样一来,我们就能通过JavaScript动态计算并动态设置<html>的font-size,来实现不同屏幕上的等比缩放。
这是很多老项目中“适配套件”的标配做法,市面上有很多现成方案,比如rem的经典实现:
// 动态设置根字体大小的核心逻辑 (function (doc, win) { var docEl = doc.documentElement, resizeEvt = 'orientationchange' in window ? 'orientationchange' : 'resize', recalc = function () { var clientWidth = docEl.clientWidth; if (!clientWidth) return; // 以设计稿宽度750px为例,当屏宽750px时,根字体大小为100px // 那么设计稿上20px的元素宽度,写成0.2rem即可 docEl.style.fontSize = 100 * (clientWidth / 750) + 'px'; }; if (!doc.addEventListener) return; win.addEventListener(resizeEvt, recalc, false); doc.addEventListener('DOMContentLoaded', recalc, false); })(document, window);这段代码的逻辑很直白。假设设计稿是750px宽(这是很多UI稿的常用宽度),屏幕宽度正好是750px时,根字体是100px,写起来非常方便:设计稿标多少px,你就除以100,填写对应的rem值。比如设计稿上有个按钮宽度是300px,那在代码里就是width: 3rem。屏幕变成375px窄的时候,根字体变成50px,3rem实际渲染就是150px,等比缩放,非常优雅。
但是,rem是有大坑的。
首先是字体缩放问题。如果你用rem作为font-size的单位,那么用户的浏览器“最小字号”设置可能会让它失效。比如Chrome对中文的最小字号限制是12px,如果rem算出来是8px,那渲染的时候就会变成12px,导致布局错乱。而且某些安卓设备的系统字体大小设置,只对px生效,对rem生效逻辑也不一致。
还有一个很骨感的现实:使用rem会导致页面整体缩放,包括图片、边框、间距。这在有些场景是好事(等比缩放),但在有些场景是坏事。比如,屏幕越宽的设备,字号应该越大;屏幕越窄,字号应该越小。你用rem等比缩放,有时候字号会小到看不清,或者大到没边。
所以我的建议是:大布局、间距、宽高,适合用rem来等比缩放;但正文字号,还是用px搭配媒体查询来处理更稳。很多人以为rem是移动端万能药,其实它只是“弹性布局”的一种手段,并不是万能的。
2.3 现代vw/vh方案:不再依赖JavaScript
近几年的新项目,我更倾向于用vw/vh视口单位。vw是视口宽度的1%,vh是视口高度的1%,它们天然跟视口尺寸挂钩,不需要任何JavaScript去动态计算。
还是以750px宽的设计稿为例:1vw=750px的1% =7.5px。所以设计稿上一个300px宽的元素,我可以直接用40vw表示。
但是,用vw之后你会发现一个蛋疼的问题:换算太麻烦。所以优选方案是配合PostCSS插件,比如postcss-px-to-viewport,在构建阶段自动把你的px转换成vw。
你直接在代码里写:
.box { width: 300px; height: 150px; }构建工具会自动变成:
.box { width: 40vw; height: 20vw; }这非常方便,你写代码的思路完全不用变,照着设计稿标注的px写就行,剩下的交给插件。这种方案的另一个好处是没有JavaScript参与,首屏不依赖JS执行,也不会有“闪一下”的字体/布局跳动问题。
需要注意的地方是**vh要慎用**,尤其是在手机浏览器上。移动端浏览器的地址栏是动态显隐的,比如你向上滑动页面,地址栏收起,视口高度就变大了;向下滑动,地址栏出现,视口高度变小。这个变来变去的过程,会导致vh计算的元素高度一直跳动,很影响体验和性能。所以,凡是依赖高度的单位,我建议优先考虑用100dvh(dynamic viewport height,动态视口高度)或者干脆用flex布局来撑,而不是直接用100vh写死。
还有一个vw的坑是边框和圆角。你如果对整个页面等比缩放,那不同屏幕上边框的视觉粗细会不一致,有时候显得很怪。所以边框、圆角、阴影这类“修饰性”的视觉元素,我建议还是用px固定数值,不要被缩放影响,这样视觉效果更稳定。
2.4 媒体查询与断点:必要的时候还是要“分治”
在上面的两种方案之上,你永远都绕不开媒体查询(Media Query)。因为等比缩放解决的是“同一个设计稿的缩放”,但有些交互和布局,在极小屏和极大屏上的合理性是完全不同的。
比如你的工具栏有四个按钮,在390px宽的屏幕上排一行正好,但在320px的旧iPhone上就挤得不行了。这时候等比缩放是没用的,需要专门针对小屏做布局调整(比如隐藏部分文字标签、缩小间距)。媒体查询就是干这个的。
/* 默认样式 */ /* 窄屏(小于320px)时的特殊处理 */ @media screen and (max-width: 320px) { .toolbar__item { flex: 1 1 25%; font-size: 12px; } } /* 宽屏(大于768px)时可以考虑平板布局 */ @media screen and (min-width: 768px) { .container { max-width: 750px; margin: 0 auto; } }我这里刻意给了一些“异常断点”。很多人喜欢拿iPhone 6/7/8的375px、iPhone 12/13的390px这种“真机宽度”来设断点,但实际意义不大,因为你不能保证每个设备间距都是一样的。更好的做法是:以“内容是否变得不合理”为断点设置的唯一依据。
比如说,我做了个卡片列表,要求卡片最小宽度是160px。如果一行排不下,我就让卡片换行。这种自适应行为用CSS Grid的auto-fill, minmax就能轻松解决,根本不需要媒体查询:
.card-list { display: grid; grid-template-columns: repeat(auto-fill, minmax(160px, 1fr)); gap: 12px; }所以,媒体查询应该是你“弹性方案的补丁”,而不是“布局的主要手段”。主框架用vw/rem弹性缩放,遇到实在不合理的临界情况,再上媒体查询修修补补,这是比较成熟的工程化思路。
3. 深水区实战:那些文档不会写的一线细节
3.1 1px物理像素线是怎么画出来的?
在各式机型上,border: 1px solid #eee这种写法,在dpr=2或3的屏幕上看起来足足有2px或3px物理像素那么粗,跟设计稿一比很明显变“脏”了。这个问题的解决方案有好几种,我推荐最实用的一种——伪元素+transform缩放。
.hairline { position: relative; } .hairline::after { content: ''; position: absolute; top: 0; left: 0; width: 200%; height: 200%; border: 1px solid #eee; transform: scale(0.5); transform-origin: 0 0; box-sizing: border-box; pointer-events: none; }逻辑是这样的:先用伪元素画一个1px边框,然后把它放大到200%的大小(此时边框也跟着放大到了2px),再用transform: scale(0.5)把整个伪元素缩小回原来尺寸,这样边框就被压缩到物理1px的视觉粗细了。在dpr=2的屏幕上,1个CSS像素 = 2个物理像素,缩小一半后等于1物理像素;在dpr=3的屏幕上,如果你把伪元素放大到300%,缩小到1/3,也是一样的效果。
但实际情况中,我们不可能为每个设备都写一套系数。所以更通用的做法是写成CSS变量或者通过Sass/Less的mixin去计算:
@mixin hairline($color: #eee) { position: relative; &::after { content: ''; position: absolute; top: 0; left: 0; width: 200%; height: 200%; border: 1px solid $color; transform: scale(0.5); transform-origin: 0 0; box-sizing: border-box; pointer-events: none; } }还要注意,scale(0.5)这只对dpr=2的设备完美。如果你非要覆盖dpr=3,可以用@media (-webkit-min-device-pixel-ratio: 3)再调整缩放比例。不过说实话,0.5这个方案在绝大多数场景下视觉上已经很接近了,肉眼基本分辨不出来,可以放心用。
3.2 安全区适配:iPhone刘海和底部小黑条的应对
“安全区”(Safe Area)这个词,做移动端开发的人不陌生。iPhone X以后,屏幕有圆角、有刘海、底部还有Home Indicator,如果你把页面内容延伸到屏幕底部,就会被那条小黑条挡住,操作按钮点不到。所以必须给内容区域留出足够空间。
最推荐的方案是使用viewport-fit=cover和env(safe-area-inset-*)。在viewportmeta标签上加上viewport-fit=cover,允许页面延伸到屏幕边缘(充全面屏),然后通过env()函数获取插值:
<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover">/* 底部安全区适配 */ .bottom-bar { padding-bottom: constant(safe-area-inset-bottom); /* iOS 11.0-11.2 */ padding-bottom: env(safe-area-inset-bottom); /* iOS 11.2+ */ }safe-area-inset-bottom在无刘海设备上返回0,在iPhone X以上的设备上返回一个数值(通常34px左右)。这个方案很干净,不需要JavaScript判断机型。安卓这边,有全面屏手势导航的机型,也存在底部安全区,新版本浏览器也已经支持env()了。建议统一处理。
另外需要注意的是,如果页面是全屏游戏或者视频播放页,你还可能要自己内边距来处理顶部的状态栏避让。通常是:
.status-bar-padding { padding-top: constant(safe-area-inset-top); padding-top: env(safe-area-inset-top); }还可以通过JavaScript获取更精确的安全区高度,但env()已经覆盖了绝大部分场景。记住,安全区适配不要搞成“一刀切”加固定值,因为每个机型的数值不一样,用env()动态获取才是正解。
3.3 横竖屏切换与动态高度问题
移动端一个很容易被忽略的真实场景是:用户会旋转手机。而且现在很多安卓机,横屏模式其实是“强制应用旋转”,CSS的媒体查询是能感知到方向的:
@media screen and (orientation: portrait) { /* 竖屏样式 */ } @media screen and (orientation: landscape) { /* 横屏样式 */ }但光有这个还不够,因为横屏时视口宽度变成了原来的高度,很多vh、vw方案会瞬间崩掉。尤其是如果你用了100vh来做一个全屏容器,在横屏且地址栏可见的时候,底部会被挡住。这个问题的现代解法是使用新的视口单位:
.fullscreen { height: 100vh; /* 兜底 */ height: 100dvh; /* 动态视口高度 */ height: 100svh; /* 最小视口高度 */ }dvh(dynamic viewport height)会实时跟随视口变化,svh(small viewport height)是地址栏完全展开时的视口高度,lvh(large viewport height)是地址栏收起时的视口高度。优先级上,建议用svh来做“全屏容器”,因为它始终是安全的——内容一定能完整的显示在地址栏展开后的视口内,而dvh有跳动风险。
在横屏场景下,经常出现的问题是“键盘弹起后布局被顶上去”。这个在下一节细聊。对于横屏适配的核心思想,我认为是:不要盯死横向宽度,把内容做成可滚动的。横屏本来就高了,宽度反而变短,所以很多竖屏时并排的列表,横屏反而要改成单列纵向排列。媒体查询在这里就是主角了。
3.4 软键盘弹起导致布局错乱怎么破?
移动端开发另一个让人头疼的问题:输入框聚焦时,软键盘弹起,把页面顶上去、按钮挡住、或者布局整个乱掉。这个问题根源在于,移动端浏览器的软键盘弹起会触发resize事件(部分浏览器),但视口的高度变化方式不一样。
解决思路有这么几条:
- 避免使用
100vh做底部定位。很多人喜欢把底部按钮用position: fixed; bottom: 0; height: 100vh这种方式搞,键盘一弹,100vh就变化了,按钮就飞到键盘后面去了。改用position: sticky或者flex布局,让底部按钮跟随内容流动,能规避很多问题。 - 监听
resize事件做补偿。在部分安卓浏览器上,键盘弹起会导致window.innerHeight变小,你可以检测到高度变化,然后给底部按钮加一个transform: translateY(-键盘高度px)之类的操作。但这段逻辑非常脆弱,容易误判,不太推荐当首选方案。 - 尽量用系统原生滚动容器。给需要滚动的区域设置
overflow-y: auto,让键盘弹起时,滚动容器自动把焦点元素滚到可视区域。移动端浏览器比如Safari有自动焦点滚动行为,你只需要保证输入框没有被fixed元素遮挡即可。
我个人经验是:最稳的做法是,让输入框位于正常文档流中,不要用fixed固定,保证键盘弹起时页面可以滚动到输入框。很多H5页面为了模仿原生的“弹层输入框”,用了fixed底部,结果键盘一弹用户就痛苦不堪。真要搞弹层输入,也得用position: fixed+resize监听,并且要在安卓和iOS上分别测试。
3.5 图片适配与加载优化
移动端适配不只是布局的事,图片也是重灾区。一张1920px宽的大图,在375px宽的手机上渲染,浏览器也要下载全图,既浪费流量又拖慢加载。而且高清屏和普通屏对图片清晰度的需求也不同,这就引入了响应式图片(srcset+sizes)。
<img src="img-375.jpg" srcset="img-375.jpg 375w, img-750.jpg 750w, img-1125.jpg 1125w" sizes="(max-width: 480px) 100vw, 750px" alt="示例图片">这个写法的意思是:当视口宽度小于480px时,图片按100vw宽度显示;否则按750px显示。srcset里的375w表示这张图适合375px宽的槽位。浏览器会根据设备dpr和视口宽度综合判断,挑一张最合适的图来加载。
如果项目里用的是CSS背景图,也可以用image-set():
.banner { background-image: image-set( url("banner-1x.png") 1x, url("banner-2x.png") 2x, url("banner-3x.png") 3x ); }在图片加载优化上,我强烈建议使用现代图片格式WebP/AVIF,体积能小个30%-70%,清晰度还不会打折扣。再加上懒加载(loading="lazy"),首屏速度能提升一大截。
此外,在很多活动页里,图片是撑满全屏宽度的。这时候用max-width: 100%; height: auto这种“流体图片”是标配,但要注意,对于一些大尺寸图片,height: auto在安卓上偶尔会有“高度计算闪跳”问题。这时候建议父容器给一个aspect-ratio,预先占好高度。
4. 常见问题与排查技巧实录
4.1 一张表格看懂常见“疑难杂症”
| 问题现象 | 可能原因 | 推荐解法 |
|---|---|---|
| 页面字体过小或过大 | rem换算错误、系统字体缩放 | 统一html根字体基准,正文建议用px搭配媒体查询 |
| 1px边框过粗 | 没有做物理像素处理 | 伪元素+transform: scale(0.5) |
| 顶部总有白条/刘海遮挡 | 未做安全区避让 | viewport-fit=cover+safe-area-inset-* |
| 底部按钮被Home条挡住 | 无视安全区 | padding-bottom: env(safe-area-inset-bottom) |
| 键盘弹起按钮跑偏 | fixed定位+100vh滥用 | 改用文档流布局、监听resize做补偿 |
| 横屏时布局像“坨屎” | 视口宽度变化导致比例失调 | 媒体查询纵向调整,容器允许滚动 |
| 安卓图上发虚/模糊 | 使用了过低分辨率的图片 | srcset+sizes让浏览器自动选图 |
| 页面加载白屏,首屏很慢 | 图片未懒加载、JS阻塞 | 懒加载、压缩图片、优化JS执行时机 |
4.2 真机调试技巧分享
最后,聊聊很多人忽略的“适配验证”环节。你不真机测一下,永远不知道你的页面在真实设备上会出什么幺蛾子。当然,不可能每台机器都买,所以分享几个替代方案:
- 使用浏览器开发者工具的“设备模拟”模式。Chrome DevTools的设备模式可以模拟各种机型的分辨率和dpr,还能触摸模拟。适合快速排查布局问题。
- 免费在线真机测试平台。比如BrowserStack、Sauce Labs这种云端真机平台,可以测试iOS和Android上的Safari/Chrome,虽然排队慢,但关键时刻能救命。
- 本地局域网真机联调。如果你电脑和手机在同一个WiFi下,用
npm run dev --host把本地开发服务器暴露到局域网,手机直接扫二维码访问。这是日常开发最顺手的调试方式,可以实时看到改动的效果。 - 利用远程调试工具。安卓端用Chrome的
chrome://inspect,iOS端用Safari的“开发”菜单,可以实时查看console日志、网络请求、甚至调试JS,定位适配问题的速度能快很多。
我在实际开发中,一个屡试不爽的“笨办法”是:把你最常用的手机设为基准机,再找一台另一种屏幕尺寸的手机作为对照机。每做完一个页面,两台机器一起过一遍主要交互流程,基本能覆盖大部分适配问题。
5. 移动端性能优化与未来适配思路
5.1 适配不只是“看得清”,还要“跑得快”
屏幕适配解决的是“长什么样”的问题,但用户体不体验流畅,还取决于页面性能。尤其是移动端网络环境复杂、CPU/GPU资源有限,稍微不注意就卡成PPT。
几个优化要点:
- 减少主线程阻塞:把大JS文件拆分、按需加载,避免阻塞首屏渲染。移动端性能优化(也是热词里的关键词)的很大一方面就是缩短首屏可交互时间。
- 利用CSS交互动画替代JavaScript动画:能用
transition、animation做的效果,就别用JavaScript频繁操作DOM。移动端GPU合成性能远高于CPU重绘。 - 浏览器缓存策略:给静态资源设置强缓存,减少二次访问时的网络请求。
- 字体文件极简化:中文字体动辄好几MB,不要整包引入,用
unicode-range按需加载子集字体,或者直接放弃自定义字体。 - 骨架屏与预渲染:移动端渲染速度不佳,首屏用骨架屏(Skeleton)占位,能显著降低白屏焦虑感。热词里提到的“前端sdk”、“前端组件库”,在实际工程里也都应该考虑这些性能基线。
这些优化思路和适配方案是“相辅相成”的关系——适配做得再好,如果性能跟不上,页面照样口碑扑街。
5.2 fcitx5在Wayland下的键盘适配问题是个很好的类比
热词里出现了一个看起来跟前端无关的Linux/输入法问题:“fcitx 在 kde wayland 应由 kwin 启动从而使用 wayland 输入法前端”。但这里面隐藏了一个移动端适配非常核心的哲学——“前端”与“后端”环境兼容。
输入法在Wayland下的问题,本质上和移动端适配遇到的问题是同一类问题:不同的图形环境(Wayland vs X11)有不同的规范,你如果沿用旧环境的假设,就会出各种bug(弹窗定位错误、输入框不聚焦、候选词条位置错乱)。同理,移动端适配也是要搞清楚你在什么环境里跑:是刘海屏、不是普通屏?有没有安全区?是不是横屏?有没有键盘弹出?所有这些问题都是“环境适配”。
理解了这一点,你再去回看整篇文章,就会发现移动端适配其实没那么神秘。它就是让你的前端代码在各个移动端环境里都能以最合理的方式工作。跟输入法要适配Wayland、RK3588要适配MIPI屏幕、Unity输入框要适配不同分辨率,都是同一条底层逻辑。
5.3 未来趋势:容器化适配与跨端方案
最后聊聊趋势。现在的移动端适配,已经从单纯的“CSS单位换算”,演进到跨端(跨平台)统一的层面。像Flutter、React Native、uni-app、Taro这些跨端框架(也是热词里频繁出现的“前端框架”),它们各自的渲染引擎和布局系统都有内置的适配方案,但这不代表前端适配的知识过时了。
恰恰相反,很多跨端项目里出现的适配问题,比纯Web更隐蔽。比如Flutter的MediaQuery、uni-app的rpx单位、React Native的PixelRatio,它们都是对“同一套逻辑”的不同皮肤。你如果理解了我上面提到的dpr、视口、安全区这些底层概念,切到哪个框架,思路都是通的。
我个人判断,未来的适配方案会更加标准化:浏览器和系统的手势导航、安全区规范会逐步统一,dvh/svh/lvh这类新单位也会逐渐替代手动计算。前端开发者的重心,会从“怎么调单位”转向“怎么让页面在各种复杂环境下都优雅地工作”——这包括无障碍、性能、动效、离线可用等等。
6. 写给新手的最后三点建议
讲了这么多,最后精简成三句话:
第一,不要迷信任何单一方案。rem有它的场景,vw/vh有自己的优势,媒体查询永远是补充,安全区适配和真机调试缺一不可。成熟的团队,都是“组合拳”。
第二,把你的设计稿和CSS保持“一比一”的状态,然后通过构建工具做转换,而不是手动去算各种换算。这样开发效率最高,也最不易出错。如果你还在手动算rem,建议升级到postcss-px-to-viewport或类似工具。
第三,真机永远是你的最终裁判。模拟器里看起来再完美,都不如用户手里那台两千块的安卓机真实。做适配,本质上是在为五花八门的设备服务,而不是为你的开发机服务。多测,准没错。