根本原因是 flex-shrink 默认为1导致小屏下子项被压缩错位,叠加软键盘触发重排、ios安全区遮挡、touch-action缺失等多重因素共同造成。

为什么移动端级联选择器在 Flex 布局下容易错位
根本原因不是 Flex 本身有问题,而是开发者常忽略 flex-shrink 默认为 1 —— 当容器宽度不足时,子项会被强制压缩,导致文字截断、按钮挤压、甚至列宽崩塌。尤其在 iOS Safari 中,input 或 select 触发软键盘后视口高度突变,触发重排,Flex 容器又没设 min-width 或 flex-basis,列宽就“随机”缩放。
- 级联选择器常见结构是
.picker-row包含多个.picker-col,每个列内有ul+li滚动项 - 若直接对
.picker-col设flex: 1,在 320px 宽屏上三列会各自分得约 106px,但字体大小、padding、border 全按 16px/1rem 写死,实际内容撑不开 - Android WebView 对
flex-wrap: wrap支持不稳定,加了反而让多列“换行”,破坏级联逻辑
用 flex-basis + min-width 锁定列宽比例
不靠百分比,也不靠 flex: 1 均分,而是用设计稿基准(如 750px)反推最小安全列宽。例如三列级联中,第一列占 30%、第二列 40%、第三列 30%,对应 750px 下为 225px / 300px / 225px —— 这些就是 min-width 的锚点值。
- 给每列加
flex: 0 0 calc(30% - 2px)(减去边框或间隙),再叠加min-width: 225px,确保小屏下不跌破可用阅读宽度 - 根容器必须设
display: flex和overflow-x: auto,防止整行被挤出视口;同时加-webkit-overflow-scrolling: touch提升 iOS 滚动流畅度 - 避免在
.picker-col上写width: 30%:百分比基于父容器计算,而父容器宽度受软键盘弹出影响剧烈,结果不可控
vh 与 max-height 配合控制滚动区域高度
级联选择器的 ul 滚动区不能写死 height: 200px,否则在 iPhone 15 Pro Max(920px 高)和旧款 Android(568px 高)上体验割裂。正确做法是用视口单位约束,再用 max-height 防溢出。
- 滚动容器设
max-height: 50vh,保证最多占屏幕一半;再加height: fit-content让内容自然撑开,避免空白拉伸 - 关键补丁:
ul { height: 100%; overflow-y: scroll; }必须配合scroll-behavior: smooth,否则 iOS 滚动卡顿明显 - 慎用
100vh:Safari 在地址栏收起/展开时会触发resize,但100vh不会重算,导致滚动区突然变矮,内容被切掉
适配刘海屏与底部安全区的 padding 处理
级联选择器常作为全屏弹层(position: fixed; top: 0; left: 0; width: 100%; height: 100%),但 iPhone X 及之后机型的底部安全区会让最后一列按钮被遮挡,且无法靠 body 的 env(safe-area-inset-bottom) 直接生效——因为级联容器通常不在 body 根层级。
- 在级联容器上直接写
padding-bottom: env(safe-area-inset-bottom),并确保该容器有background覆盖,否则安全区会透出底色 - 搭配媒体查询做降级:
@supports (padding-bottom: env(safe-area-inset-bottom)) { ... },老设备自动忽略 - 不要只依赖 JS 动态计算
innerHeight:部分安卓 WebView 返回的是 layout viewport 高度,不是视觉视口,算出来偏差达 100px+
最易被忽略的一点:级联选择器的 touch-action: manipulation 必须加在每列容器上。否则 iOS 上快速滑动 ul 时,系统会优先触发双指缩放或长按菜单,导致滚动中断。这个属性不继承,写在父级无效。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











