移动端适配问题记录

1px适配

  在 Retina 屏(DPR ≥ 2)上,CSS 的 1px 在物理上其实是 2px 或 3px,看起来比设计稿粗一圈。下面是几种常用的解决方案。

方案一:transform scale 模拟

  用伪元素画一条 1px 的线,然后通过 scaleY(0.5) 在垂直方向压缩一半:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
.hairline {
position: relative;
}
.hairline::after {
content: '';
position: absolute;
left: 0;
bottom: 0;
width: 100%;
height: 1px;
background: #ccc;
transform: scaleY(0.5);
transform-origin: 0 0;
}

  同理,scale(0.5) 可以做完整的 1px 边框:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
.border-1px {
position: relative;
}
.border-1px::after {
content: '';
position: absolute;
left: 0;
top: 0;
width: 200%;
height: 200%;
border: 1px solid #ccc;
border-radius: 4px;
transform: scale(0.5);
transform-origin: left top;
pointer-events: none;
}

方案二:用 0.5px

  部分现代浏览器(iOS 8+)支持 0.5px 写法,但兼容性有限:

1
2
3
.border-thin {
border-width: 0.5px;
}

方案三:viewport 缩放(不推荐)

  通过修改 viewport 的 scale 来让 1px 对应 1 个物理像素。但会影响整个页面的布局和 rem 计算,副作用大,很少用。

系统软键盘对 fixed 布局影响

  移动端最头疼的问题之一。当页面底部有个 fixed 定位的输入框/按钮时,软键盘弹出会导致布局错乱。

问题表现

  点击底部固定输入框 → 软键盘弹出 → position: fixed 的元素不再相对视口定位,而是相对键盘上方的可视区域定位。导致:

  • 底部固定栏被顶到键盘上方
  • 键盘收起后底部固定栏没有回到原位
  • Android 上表现尤其混乱(不同厂商差异大)

解决思路

1. 避免在底部 fixed 元素中使用输入框

  最简单的方案:将底部固定栏改为 position: static,在键盘弹出时自动滚动到可视区域。或者让输入框在获得焦点时固定在顶部。

2. 用视口单位 + 页面滚动代替 fixed

1
2
3
4
5
6
7
8
9
10
11
12
.fixed-bottom {
position: fixed;
bottom: 0;
left: 0;
right: 0;
}

@media screen and (max-height: 500px) {
.fixed-bottom {
position: static;
}
}

3. 监听 resize 或 focusin/focusout

1
2
3
4
5
6
7
8
9
10
11
12
13
const bottomBar = document.querySelector('.fixed-bottom');

window.addEventListener('resize', () => {
if (document.activeElement.tagName === 'INPUT' ||
document.activeElement.tagName === 'TEXTAREA') {
bottomBar.style.position = 'static';
}
});

document.addEventListener('focusout', () => {
bottomBar.style.position = 'fixed';
window.scrollTo(0, document.body.scrollHeight);
});

4. 使用 VisualViewport API(现代方案)

1
2
3
4
5
6
7
8
9
10
11
if (window.visualViewport) {
window.visualViewport.addEventListener('resize', () => {
const diff = window.innerHeight - window.visualViewport.height;
if (diff > 100) {
bottomBar.style.position = 'static';
} else {
bottomBar.style.position = 'fixed';
bottomBar.style.bottom = '0';
}
});
}

经验总结

  • iOS:相对友好,键盘弹出后 fixed 元素的定位还比较稳定
  • Android:碎片化严重,不同厂商(华为、小米、三星)表现差异大,建议在真机上测试
  • 最稳妥的做法还是不要让输入框放在 fixed 栏里,改成随页面滚动