You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

粘性定位入场、非粘性退场(无JS):多sticky元素同步退场实现方案问询

实现多个sticky元素同步被推出屏幕的方案

这个需求确实没法用纯原生position:sticky的默认行为实现,因为每个sticky元素的“粘性脱离点”是独立的——当元素的top偏移加上自身高度触达父容器底部时,就会开始被滚动推出。要让它们同步,我们需要把它们的位置变化绑定到同一个滚动进度上,下面给你两个可行的方案:

方案一:CSS滚动驱动动画(现代浏览器推荐)

这个方案利用CSS的scroll-timeline特性,把三个元素的动画绑定到主容器的滚动进度上,实现同步位移,完全不需要JS:

修改后的CSS代码

html,body{width:100%;height:100%;margin:0}
main{width:57.5vh;height:375vh;position:absolute;left:50%;transform:translateX(-50%);font-family:arial black;color:#fff;background:gold;
  /* 定义滚动时间线,绑定main元素的滚动 */
  scroll-timeline: --main-scroll block;
}
.title{--height:25vh;height:var(--height);text-align:center;line-height:var(--height)}
.e{background:pink}
.o{background:skyblue}
main>div:nth-child(1){height:100vh}
main>div:nth-child(2){z-index:5;top:0;position:sticky} /* STEP: 1 */
main>div:nth-child(3){height:75vh}
/* 调整父容器为relative,让内部的固定容器基于它定位 */
main>div:nth-child(4){height:150vh;position:relative;border:solid red 2px;box-sizing:border-box;}
/* 新增粘性容器,作为三个STEP元素的定位基准 */
.sticky-group{
  position: sticky;
  top: 0;
  height: 100%;
  position: relative;
}
/* 给三个STEP元素添加滚动驱动动画 */
.sticky-step{
  position: absolute;
  left: 0;
  width: 100%;
  animation: sticky-slide linear forwards;
  animation-timeline: --main-scroll;
  /* 动画触发范围:根据你的布局计算,从滚动到STEP4即将被推出的位置,到完全推出的位置 */
  animation-range: 400vh 550vh;
}
.sticky-step:nth-child(1){top:25%}
.sticky-step:nth-child(2){top:50%}
.sticky-step:nth-child(3){top:75%}
/* 定义同步推出的动画 */
@keyframes sticky-slide {
  to {
    transform: translateY(100vh); /* 把元素整体向下推出视口 */
  }
}
.gap{height:100vh;background:limegreen}

修改后的HTML代码

<main>
  <div></div>
  <div class='title e'>STEP: 1</div>
  <div></div>
  <div>
    <div class="sticky-group">
      <div class='title o sticky-step'>STEP: 2</div>
      <div class='title e sticky-step'>STEP: 3</div>
      <div class='title o sticky-step'>STEP: 4</div>
    </div>
    <div></div>
    <div></div>
    <div></div>
    <div class='gap'>GAP</div>
  </div>
</main>

原理说明

我们把三个STEP元素从原来的流式布局中抽离,放到一个sticky的容器里,用绝对定位固定它们的初始位置。然后通过scroll-timeline绑定主容器的滚动进度,当滚动到指定范围时,触发同步的translateY动画,让三个元素一起被推出屏幕。

方案二:JavaScript滚动监听(兼容旧浏览器)

如果需要兼容不支持scroll-timeline的浏览器,可以用JS监听滚动事件,动态计算滚动进度来控制元素的位移:

修改后的CSS代码

html,body{width:100%;height:100%;margin:0}
main{width:57.5vh;height:375vh;position:absolute;left:50%;transform:translateX(-50%);font-family:arial black;color:#fff;background:gold;overflow-x:hidden}
.title{--height:25vh;height:var(--height);text-align:center;line-height:var(--height)}
.e{background:pink}
.o{background:skyblue}
main>div:nth-child(1){height:100vh}
main>div:nth-child(2){z-index:5;top:0;position:sticky} /* STEP: 1 */
main>div:nth-child(3){height:75vh}
main>div:nth-child(4){height:150vh;position:relative;border:solid red 2px;box-sizing:border-box;}
.sticky-group{
  position: sticky;
  top: 0;
  height: 100%;
  position: relative;
}
.sticky-step{
  position: absolute;
  left: 0;
  width: 100%;
  transition: transform 0.1s ease; /* 让位移更平滑 */
}
.sticky-step:nth-child(1){top:25%}
.sticky-step:nth-child(2){top:50%}
.sticky-step:nth-child(3){top:75%}
.gap{height:100vh;background:limegreen}

JavaScript代码

const main = document.querySelector('main');
const stickySteps = document.querySelectorAll('.sticky-step');
// 计算触发同步推出的滚动位置范围(单位vh)
const triggerStart = 100 + 25 + 75 + 150 - 100; // 前面元素的总高度减去视口高度,即STEP开始要被推出的位置
const triggerEnd = triggerStart + 100; // 滚动100vh后完全推出

main.addEventListener('scroll', () => {
  const scrollTop = main.scrollTop;
  const vh = window.innerHeight * 0.01; // 1vh对应的像素值
  const startPos = triggerStart * vh;
  const endPos = triggerEnd * vh;

  if (scrollTop >= startPos && scrollTop <= endPos) {
    // 计算当前滚动进度(0到1)
    const progress = (scrollTop - startPos) / (endPos - startPos);
    // 给所有STEP元素应用同步位移
    stickySteps.forEach(step => {
      step.style.transform = `translateY(${progress * 100}vh)`;
    });
  } else if (scrollTop > endPos) {
    // 完全推出屏幕
    stickySteps.forEach(step => {
      step.style.transform = `translateY(100vh)`;
    });
  } else {
    // 回到初始位置
    stickySteps.forEach(step => {
      step.style.transform = `translateY(0)`;
    });
  }
});

原理说明

通过监听主容器的滚动事件,计算当前滚动位置是否在触发范围内,然后根据滚动进度动态设置所有STEP元素的transform属性,让它们同步向下移动,模拟“一起被推出”的效果。

为什么原方案无法实现?

原方案中每个sticky元素的粘性上下文是它们的父容器,当父容器滚动时,每个元素会在自身的top偏移加上高度触达父容器底部时,开始脱离粘性状态被推出——因为它们的top值不同,所以触发时机也不同,自然会逐个被推出。我们的方案是脱离原生sticky的独立触发逻辑,改用统一的滚动进度来控制位置,从而实现同步效果。

内容的提问来源于stack exchange,提问作者oldboy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.30 08:49:05