时间轴 sticky 失效主因是结构问题:flex 容器未设 align-items: flex-start、祖先含 transform/filter、容器缺失滚动上下文;须设 max-height+overflow-y:auto、overflow:clip、双前缀,Safari 不稳时降级 fixed+JS。

时间轴节点用 position: sticky 吸附,不是加了 top: 0 就能动——它极容易被 flex 容器、transform 父层或滚动容器缺失高度直接废掉。
为什么时间轴里 sticky 节点“卡半截”或完全不动
不是写法错,是结构天然触发 sticky 失效链:时间轴常嵌在 display: flex 容器里,而父容器没设 align-items: flex-start,导致节点初始位置被居中,top: 0 实际计算出负偏移;更常见的是祖先元素加了 transform: translateY(0) 或 filter: opacity(1),Chrome 和 Safari 都会直接禁用 sticky;还有就是时间轴容器本身没设 height 或 max-height + overflow: auto,没有自己的滚动上下文,sticky 只能退化为 relative。
调试时打开开发者工具,选中节点,在「Computed」里看 position 是否真解析为 sticky,再检查 top 值是否被重写或继承为 auto。
时间轴容器必须自己滚动,不能靠 body
时间轴(比如 .timeline)必须有明确的滚动能力,否则所有子节点的 sticky 都找不到参考容器:
立即学习“前端免费学习笔记(深入)”;
- 设
max-height: 600px+overflow-y: auto(不能是hidden或scroll) - 避免用
overflow: clip以外的裁剪方式——clip允许 sticky 生效,hidden会直接切断 - 如果容器是
display: flex,必须同步加align-items: flex-start,否则子项垂直居中会干扰top的基准线 - 不要给容器或任意祖先加
contain: layout paint或backface-visibility: hidden,Safari 会直接忽略 sticky
节点层级与填充效果的关键写法
纯 CSS 实现“滚动即填充”的时间轴线条,靠的是两个 sticky 层级的错位,不是单个节点吸顶:
- 每个时间点用
.timeline-point包裹,其内部放一个.active-line -
.timeline-point设position: sticky; top: 0;,并确保它有明确高度(比如min-height: 80px) -
.active-line用position: absolute; bottom: 0; height: 100%; width: 2px; background: #3b82f6;,初始被父容器裁剪 - 外层时间轴容器必须设
overflow: clip(不是hidden),否则absolute子元素无法随父 sticky 滚动逐步露出 - 基线(
.baseline)用普通position: relative+z-index: 1,确保始终在底层不干扰
Safari 下 sticky 失效的硬性补救措施
Safari 对 sticky 更敏感,尤其 iOS 15.4 之后仍存在回滚抖动和偶发失效:
- 必须写双前缀:
position: -webkit-sticky;放在position: sticky;前面 - 删掉所有祖先上的
transform(包括translateZ(0))、filter、will-change - 避免用
margin-top: auto或align-self: center控制节点位置,改用padding-top或显式align-self: flex-start - 若仍不稳定,降级方案:用
@supports not (position: sticky)给 Safari 单独切到position: fixed+ JS 监听scroll动态更新top
最易被忽略的一点:时间轴节点的 top 值永远是相对于它最近的、有滚动行为的父容器内容区顶部,而不是视口——这意味着你调 top: 60px 是为了让节点在“容器顶部往下 60px 处”才吸附,不是“离屏幕顶部 60px”。


















