移动端适配要注意哪些问题?1px 边框怎么实现?
一句话回答
移动端适配先写好 viewport meta,让布局视口等于设备宽度;再用 rem 或 vw 方案按设计稿缩放。1px 问题来自设备像素比(DPR):CSS 的 1px 在 2 倍屏上是 2 个物理像素,看起来偏粗,常用伪元素加 transform: scale(0.5) 画出物理 1px 的线。另外要处理刘海屏的安全区域、保证点击区域足够大,以及 iOS 上输入框字号小于 16px 时聚焦会自动放大的问题。
详细解析
viewport meta
没有 viewport meta 时,移动浏览器会假设页面是给桌面设计的,用一个 980px 左右的布局视口渲染,再整体缩小显示,文字很小。标准写法是:
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
width=device-width 让布局视口等于设备的 CSS 宽度,viewport-fit=cover 让页面铺满刘海屏的整个屏幕,配合下面的安全区域使用。单位选择和 rem/vw 方案见 响应式单位。
设备像素比和 1px 问题
DPR(window.devicePixelRatio)是物理像素和 CSS 像素的比值。2 倍屏上 1 个 CSS 像素占 2×2 个物理像素。设计稿通常按 2 倍图出(例如 750 宽),设计师画的 1px 线换算到 CSS 是 0.5px,而我们写 border: 1px 实际占了 2 个物理像素,所以显得粗。
常见方案:
| 方案 | 做法 | 优缺点 |
|---|---|---|
0.5px 边框 |
直接写 border: 0.5px solid |
最简单;iOS 上支持较好,部分旧版安卓 WebView 会当成 0(不显示)或 1px,要在目标机型上实测 |
| 伪元素缩放 | 伪元素宽高 200%,画 1px 边框,再 scale(0.5) |
兼容性最好,支持圆角,最常用;占用了伪元素 |
box-shadow |
box-shadow: 0 0 0 0.5px #ddd |
写法短,颜色会偏淡 |
| viewport 缩放 | 按 DPR 把 initial-scale 设成 1/dpr |
全局生效;页面所有尺寸都要跟着放大,早期 lib-flexible 用过,现在少用 |
安全区域
刘海屏、底部有横条的手机,屏幕边缘有一部分会被遮挡。设置 viewport-fit=cover 后,用 env(safe-area-inset-top/right/bottom/left) 读出被遮挡的距离,加到吸顶、吸底元素的内边距里。不支持的浏览器里 env() 取第二个参数作为回退值。
点击区域和输入框
- 点击区域:手指比鼠标粗得多,按钮太小容易点错。WCAG 2.2 的 2.5.8(AA 级)要求点击目标至少 24×24 CSS 像素,或者和相邻目标留出足够间距;2.5.5(AAA 级)要求 44×44。移动端一般按 44×44 左右设计。图标按钮视觉上可以小,用
padding或伪元素把可点区域扩大 - iOS 输入框放大:iOS Safari 中输入框计算后的字号小于 16px 时,聚焦会自动放大页面,失焦后通常也不会自动缩回。把输入框的
font-size设为 16px 及以上就能避免,注意根字号改小后1rem可能不到 16px。有人用maximum-scale=1禁止缩放,这会影响需要放大阅读的用户,不推荐
代码示例
/* 伪元素实现物理 1px 下边框 */
.cell {
position: relative;
}
.cell::after {
content: "";
position: absolute;
left: 0;
top: 0;
width: 200%;
height: 200%;
border-bottom: 1px solid #e5e5e5;
transform: scale(0.5);
transform-origin: 0 0;
pointer-events: none; /* 不挡住点击 */
box-sizing: border-box;
}
/* 吸底操作栏避开底部横条 */
.action-bar {
position: fixed;
left: 0;
right: 0;
bottom: 0;
padding-bottom: env(safe-area-inset-bottom, 0px);
}
/* 避免 iOS 聚焦放大 */
input,
textarea,
select {
font-size: 16px;
}
面试官可能追问
伪元素方案怎么只在高倍屏上生效?
用分辨率媒体查询,例如 @media (min-resolution: 2dppx),只在 DPR 大于等于 2 时启用缩放;3 倍屏可以再写一条,用 300% 尺寸和 scale(0.333)。不过 2 倍的写法在 3 倍屏上效果也可以接受,很多项目只写一套。
软键盘弹出会带来什么问题?
键盘弹出时,可视区域变小,但不同浏览器处理方式不同:有的缩小视觉视口,fixed 吸底元素可能被顶起或被遮住;输入框也可能被键盘挡住。常见做法是监听 window.visualViewport 的 resize 事件拿到真实可视高度,或者在聚焦时调用 scrollIntoView() 把输入框滚到可见区域。
移动端的 300ms 点击延迟还存在吗?
早期移动浏览器为了判断是不是双击缩放,会把 click 延迟约 300ms。现在只要设置了 width=device-width 的 viewport,主流浏览器就不再延迟,也可以用 touch-action: manipulation 明确禁用双击缩放。所以 FastClick 这类库在新项目里已经不需要了。
易错点
- 1px 问题不是"边框画错了",而是 CSS 像素和物理像素的比例问题,只在高 DPR 屏上明显
- 伪元素缩放方案要给宿主加
position: relative,伪元素加pointer-events: none,否则会挡住点击 - 没有在 viewport meta 里设置
viewport-fit=cover时,页面不会延伸到被遮挡的区域,safe-area-inset-*通常是 0,写了env()也看不出效果
AI 模拟面试官
用自己的话回答,AI 对照参考答案打分、指出遗漏,再追问,最多 3 轮
这道题你掌握了吗?
选一个最接近的状态,没掌握的题会出现在"我的进度 · 待复习"里。
学习记录暂存在本机浏览器。登录后自动同步到账号,换设备也能看到。