加了flex-shrink: 0还不滚动,根本原因是父容器缺乏明确宽度约束,必须同时满足:父容器设width/max-width、子项设flex-shrink: 0及white-space: nowrap、子项总宽超容器宽。

为什么加了 flex-shrink: 0 还不滚动?
常见现象是:写了 display: flex、overflow-x: auto、flex-shrink: 0,但标签还是被压扁、换行、或根本没滚动条。根本原因不是属性没写,而是父容器缺乏「尺寸边界」——Flex 容器默认会随内容撑开,不触发溢出。
必须同时满足三个硬性条件:
- 父容器有明确的
width或max-width(比如width: 100%、max-width: 480px,不能只靠display: flex) - 子项设
flex-shrink: 0(或更稳妥的flex: 0 0 auto),且内部文字加white-space: nowrap+overflow: hidden+text-overflow: ellipsis - 子项真实总宽度 > 父容器可用宽度(靠图片、固定宽元素、
min-width等实际撑开,不是靠flex-basis模糊估算)
漏掉任一条件,滚动都会失效。尤其注意:iOS Safari 中若没加 -webkit-overflow-scrolling: touch,可能滑得卡顿甚至无惯性。
移动端 touchend 和 click 双触发怎么破?
点一次标签,切换两次——这是 iOS 和部分安卓机型上最典型的交互 bug。根源是浏览器在 touchend 后 300ms 补发一个 click 事件,而你两个都监听了。
标准解法只用 touchend,并统一拦截:
- 所有 tab 标签加
cursor: pointer和touch-action: manipulation - JS 中只绑定
touchend,开头加if (e.cancelable) e.preventDefault() - PC 端 fallback 要显式判断:
if ('ontouchstart' in window) return,再绑click - 绝对不要在
touchstart里调preventDefault()—— 会禁掉页面整体滚动
别用内联 onclick="xxx()",否则无法统一控制默认行为。
transform: translateX() 为什么比 left 更适合内容区滑动?
直接改 left 或 margin-left 会导致频繁重排(reflow),动画卡顿明显;而 transform: translateX() 走合成层,性能好且支持硬件加速。
关键实操要点:
- 所有内容面板必须同级排列(比如都在
.panels内),初始用position: absolute或flex: 0 0 100%并设left: 0 - 只对当前面板设
transform: translateX(0),其他设为translateX(-100%)或translateX(100%) - CSS 必须配
transition: transform 0.3s ease(ease比linear更贴合手指滑动直觉) - 切完后若面板高度不一致,得立刻调
getBoundingClientRect().height更新容器高度,否则留白或遮挡
别对 display 或 visibility 做 transition——这两个属性不可动画,浏览器直接跳变。
滑动门(indicator)定位不准的根因和修复时机
滑动门跟着当前 tab 移动时偏左、偏右、或滞后,不是 CSS 写错了,而是 JS 计算时机不对。DOM 尺寸读取和 scroll 操作混在一起,容易拿到旧值。
正确做法是把定位逻辑放进 requestAnimationFrame:
- 先更新
activeId,再触发滚动或位移 - 在
requestAnimationFrame回调里读offsetLeft、offsetWidth、scrollLeft,确保拿的是渲染后的最新布局数据 - 如果容器存在缩放(如
transform: scale(0.9)),要额外除以缩放比修正位置 - 移动端需考虑
scroll-behavior: smooth的兼容性(仅现代浏览器支持,老版 iOS 需降级为scrollLeft+setTimeout)
最易忽略的是:当标签文字长度差异大、或动态插入新 tab 时,必须重新计算所有 offsetLeft,不能缓存初始值。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











