去年冬天。一个做母婴电商的朋友半夜给我甩了张截图。
他们的商品详情页,在自家测试机上一直好好的。iPhone SE 翻一遍,红米 Note 翻一遍,看不出毛病。上线第二天客诉就来了——iPhone 15 Pro Max 上,那个「立即购买」被挤到屏幕外面,只剩半个字。
他第一反应是加 overflow: hidden。我说别急。这不是溢出,是你没搞清楚自己在跟谁对齐。

设计稿是375但手机从来不是
设计交付过来,宽度 375,正文字号 14,间距 16。就这些。前端拿到的信息量,说实话,就这么点。
可浏览器给你的东西复杂得多。布局视口、视觉视口、理想视口——三个概念,我见过做了三年移动端的人还是拎不清谁管谁。
<meta name='viewport' content='width=device-width, initial-scale=1'> 这行代码几乎每个项目的模板里都有。但它到底在干什么?它是在告诉浏览器:别自作主张,把布局视口设成设备宽度。
不写这行,iOS Safari 会默认塞给你一个 980px 宽的布局视口,然后把整页缩放了硬塞进屏幕。字小得像蚂蚁爬。很多老后台系统在手机上打开就是这副德行,怨不得用户截图发群里吐槽。
写了就完事了?也不见得。
initial-scale=1 在某些安卓机的 WebView 里会被忽略,再不然就是跟系统字体缩放打架。你在 html 上设 font-size:16px 当 rem 基准,用户跑去系统设置里把字体调成「超大」,整个页面立刻崩盘——这不是极端情况,中老年用户群的产品里,这个比例一点都不低。
所以真要上 rem 方案,光靠 CSS 是不够的。得在页面里塞一个隐藏元素,探测它实际的计算宽度,反推系统是不是动了字号。听起来脏?确实脏。但管用。
1px 和 100vh 这两对老冤家

DPR。物理像素和 CSS 像素的比值。iPhone 的 DPR 是 3,意味着一件事:你写 1px 的边框,实际占了 3 个物理像素。视觉上就粗了,糙了,跟设计稿一对比就看得出落差。
常见解法三种。伪元素配 transform: scaleY(0.333),能解决,但布局会有点飘。用 box-shadow 模拟,简单粗暴,圆角边框就搞不定了。border-image 走 SVG,最干净,代价是维护成本,换个人接手要先看懂。
选哪个?看你团队。人手紧就 box-shadow,能交差。对细节有要求的就 SVG。
100vh 更烦。iOS Safari 里,100vh 算的是地址栏收起时的高度。用户一滚动,地址栏缩回去,你那个首屏 hero 区就矮了一截,底部按钮跟着往下跳,像抽筋一样。
后来有了 dvh、svh、lvh。100dvh 是动态的,会跟着地址栏走。问题是老设备不认。安卓 8 的 WebView 直接把 100dvh 当无效值丢掉,你的元素连个高度都没有,塌成一条线。
兜底还是得靠 JS。window.innerHeight 实时算,写进 CSS 变量。丑,但稳。
那些没人写进文档的边角料

说说安全区。
iPhone 从 X 那代开始有刘海和底部横条。env(safe-area-inset-bottom) 这个环境变量,得配合 viewport-fit=cover 才有用,少一个都白搭。我见过不止一个项目,按钮就那么贴着底部横条放,用户手指一滑就误触。
还有键盘。底部固定一个输入框,用户点上去——安卓的键盘是覆盖上去的,iOS 的键盘会把整个页面往上顶。fixed 定位的元素在两种行为下表现完全不一样。想统一?用 visualViewport API 监听高度变化,手动改定位。没别的路。
折叠屏和平板更别提了。断点写了两档,1200 和 768,结果人家展开是 2200px 宽。你那套「桌面端」布局撑得整个屏幕空荡荡,中间留一大片白,像写了一半的作业。
真机才是唯一的标准答案

DevTools 能帮你七成。剩下三成,全靠真机。
几个习惯,我这些年养下来的,不一定对,但有用:
买几台便宜的二手机。安卓 7、安卓 10、iOS 13,各一台。不贵,加起来几百块,比出事之后返工的代价低太多。
认真配一次真机远程调试。Chrome 的 chrome://inspect,Safari 的开发菜单。第一次折腾可能半小时起步,配通之后就是救命工具。
把测试机清单写进项目文档。哪台机子、什么系统版本、什么内核,白纸黑字列着。产品经理排期的时候能一眼看到,就不会觉得「适配」这两个字是免费的。
别老换适配方案。今天 rem,明天 vw,后天又上 vw + rem + clamp 三件套。每换一次都是在给团队挖一个新坑,半年后没人记得当初为什么这么写。
一套方案,跑通了,就让它跑个两三年。除非真的撞了墙,不然别动它。
移动端适配是没有终点的。屏幕在变,浏览器在变,用户的手势习惯也在变。你能做的就是把根基打稳,然后每次上线之前,拿真机从头到尾过一遍。
麻烦吗。麻烦。但总比客服截图在群里刷屏强得多。