移动端显示异常的头号原因是viewport meta标签缺失或参数错误,必须设置width=device-width、initial-scale=1.0,避免user-scalable=no等影响可访问性的属性。

viewport meta 标签写不对,页面在手机上直接缩成一团
移动端显示异常的头号原因就是 <meta name="viewport"> 缺失或参数错。不加这行,iOS 和 Android 浏览器会默认按 980px 宽度渲染,再整体缩放进屏幕,文字小得看不清,点击区域错位。
必须写,且推荐用这个最小可用配置:
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
-
width=device-width是核心,它让视口宽度匹配设备物理宽度(不是固定 980) -
initial-scale=1.0防止 iOS Safari 自动缩放;不写的话,小字体内容可能被放大,大标题又被缩小 -
user-scalable=no虽然能禁双指缩放,但可访问性差,上线前建议删掉——除非是 kiosk 模式设备 - 别写
maximum-scale=1.0或minimum-scale=1.0,它们在部分安卓 WebView 里失效,还可能锁死横屏体验
CSS 中 px 单位在高 DPR 设备上模糊、发虚
iPhone 13 的 DPR 是 3,意思是 1 个 CSS 像素对应 3×3 个物理像素。如果用 border: 1px solid #ccc,浏览器会把它糊成一条半透明灰线——因为没对齐物理像素网格。
解决方法不是全换成 rem 或 em,而是按场景选:
立即学习“前端免费学习笔记(深入)”;
- 需要锐利边框(如卡片分隔线):用
transform: scaleY(0.333)配合origin控制缩放基点,或者直接上border-image切 1px 图 - 图标/装饰性线条:优先用
svg或 icon font,天然矢量,DPR 无关 - 字体大小:保持用
px,现代浏览器对font-size的 DPR 处理已很稳定;别强行转rem增加计算负担 - 避免
background: linear-gradient()模拟细线——在某些安卓低版本里会锯齿明显
flex 布局在旧版 iOS Safari 里塌陷、换行错乱
iOS 9.3 及更早的 Safari 对 flex 的实现有多个 bug,比如 flex: 1 不生效、flex-wrap: wrap 忽略 min-width、子项 margin 被吞掉。
不是所有项目都能放弃 iOS 9,稳妥做法是加一层防御:
- 给 flex 容器加
display: -webkit-box和display: -ms-flexbox回退(注意顺序:标准写法放最后) - 避免只靠
flex: 1填满剩余空间;改用flex-basis: 0+flex-grow: 1,兼容性更好 - 如果用了
flex-direction: column+height: 100vh,记得给父级也设height: 100%,否则 iOS 8–9 里子项高度算成 0 - 测试时真机连 Safari Web Inspector,别信模拟器——很多 flex 行为在模拟器里是“修好的”
图片加载慢、拉伸变形,用户划到一半才看到占位图
移动端网络波动大,图片没做响应式处理就会:带宽浪费(桌面图传到手机)、布局跳动(没设 width/height)、首屏白屏(src 写死大图)。
关键不是“用不用 srcset”,而是怎么用不翻车:
-
<img>必须带width和height属性(可以是内联 style,但不能只靠 CSS),防止重排 - 简单适配:用
srcset+sizes,例如sizes="(max-width: 768px) 100vw, 50vw",让浏览器按视口宽度选图 - 别在
srcset里混用不同 DPR 和不同尺寸的图,容易选错;同一组只变宽度(400w,800w),DPR 交给x描述符(2x)单独控制 - 懒加载用
loading="lazy"就够,别自己写 IntersectionObserver 增加 JS 执行压力——低端安卓机上 IO 观察器卡顿比图片慢更伤体验
实际适配中最容易被忽略的,是「viewport 设置后,CSS 媒体查询里的 max-width 是按视口宽度算,不是设备物理宽度」。很多人测 iPhone SE(320px 物理宽)时写 @media (max-width: 320px),结果不触发——因为视口宽度是 320 * DPR = 640px。得按 device-width 对应的视口值来写断点。











