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

求助:实现Section底部距顶部33vh时粘性定位的异常问题

问题描述

我想要实现这样的滚动过渡效果:当每个section的底部距离屏幕顶部33vh时,该section变为sticky状态,后续section滚动覆盖它。但因为各section高度不固定,基于div底部到屏幕顶部的距离设置粘性定位时出现了问题:在提供的代码示例中,Section 1被截断,末尾有大量空白,Section 4完全不可见,只有Section 2和Section 3之间的过渡符合预期。优先要纯CSS/Tailwind解决方案,不过项目是React构建且用Framer Motion做动画,也接受其他可行方案。

原代码示例

CSS

.container {
  text-align: center;
  height: 100vh;
  overflow-y: auto;
  background: black;
  margin: 0;
}

.section1 {
  position: sticky;
  top: 0px;
  display: flex;
  justify-content: space-between;
  height: 100vh;
  background: linear-gradient(180deg, blue, orange);
  flex-direction: column;
  /* hack to get top section to not be covered up by transform */
  margin-bottom: 220vh;
}

.section {
  /* translate up so that position is 0 when the last 33vh of div is visible */
  transform: translateY(calc(-100% + 33vh));
  position: sticky;
  top: 0px;
  height: 240vh;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  background: linear-gradient(180deg, blue, orange);
}

.flex-div {
  display: flex;
  flex-direction: column;
}

HTML

<div class="container">
  <div class="section1">
    <div class="flex-div">
      <h1>Section 1 top</h1>
    </div>
    <div class="flex-div">
      <h1>Section 1 bottom</h1>
    </div>
  </div>
  <div class="section">
    <div class="flex-div">
      <h1>Section 2 top</h1>
    </div>
    <div class="flex-div">
      <h1>Section 2 bottom</h1>
    </div>
  </div>
  <div class="section">
    <div class="flex-div">
      <h1>Section 3 top</h1>
    </div>
    <div class="flex-div">
      <h1>Section 3 bottom</h1>
    </div>
  </div>
  <div class="section">
    <div class="flex-div">
      <h1>Section 4 top</h1>
    </div>
    <div class="flex-div">
      <h1>Section 4 bottom</h1>
    </div>
  </div>
</div>
解决方案

纯CSS方案

核心思路

原代码的问题在于使用transform和固定高度/外边距的hack,导致布局错位。正确的做法是给每个section套一个容器,通过容器高度提供足够的滚动空间,让sticky定位自然触发:

  • 每个section容器高度设为calc(100vh + 67vh):100vh是section占满屏幕的高度,67vh是从section底部到屏幕顶部33vh所需的滚动距离
  • section设置position: sticky; top: 0; min-height: 100vh;,确保滚动到触发点时粘在顶部,后续section覆盖它

代码示例

CSS

.container {
  text-align: center;
  background: black;
  margin: 0;
}

.section-wrapper {
  height: calc(100vh + 67vh);
}

.section {
  position: sticky;
  top: 0;
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  background: linear-gradient(180deg, blue, orange);
}

.flex-div {
  display: flex;
  flex-direction: column;
}

HTML

<div class="container">
  <div class="section-wrapper">
    <div class="section">
      <div class="flex-div">
        <h1>Section 1 top</h1>
      </div>
      <div class="flex-div">
        <h1>Section 1 bottom</h1>
      </div>
    </div>
  </div>
  <div class="section-wrapper">
    <div class="section">
      <div class="flex-div">
        <h1>Section 2 top</h1>
      </div>
      <div class="flex-div">
        <h1>Section 2 bottom</h1>
      </div>
    </div>
  </div>
  <div class="section-wrapper">
    <div class="section">
      <div class="flex-div">
        <h1>Section 3 top</h1>
      </div>
      <div class="flex-div">
        <h1>Section 3 bottom</h1>
      </div>
    </div>
  </div>
  <div class="section-wrapper">
    <div class="section">
      <div class="flex-div">
        <h1>Section 4 top</h1>
      </div>
      <div class="flex-div">
        <h1>Section 4 bottom</h1>
      </div>
    </div>
  </div>
</div>

Tailwind CSS方案

直接用Tailwind类替换CSS规则,实现相同效果:

<div class="bg-black m-0 text-center">
  <div class="h-[calc(100vh+67vh)]">
    <div class="sticky top-0 min-h-screen flex flex-col justify-between bg-gradient-to-b from-blue-500 to-orange-500">
      <div class="flex flex-col">
        <h1>Section 1 top</h1>
      </div>
      <div class="flex flex-col">
        <h1>Section 1 bottom</h1>
      </div>
    </div>
  </div>
  <div class="h-[calc(100vh+67vh)]">
    <div class="sticky top-0 min-h-screen flex flex-col justify-between bg-gradient-to-b from-blue-500 to-orange-500">
      <div class="flex flex-col">
        <h1>Section 2 top</h1>
      </div>
      <div class="flex flex-col">
        <h1>Section 2 bottom</h1>
      </div>
    </div>
  </div>
  <div class="h-[calc(100vh+67vh)]">
    <div class="sticky top-0 min-h-screen flex flex-col justify-between bg-gradient-to-b from-blue-500 to-orange-500">
      <div class="flex flex-col">
        <h1>Section 3 top</h1>
      </div>
      <div class="flex flex-col">
        <h1>Section 3 bottom</h1>
      </div>
    </div>
  </div>
  <div class="h-[calc(100vh+67vh)]">
    <div class="sticky top-0 min-h-screen flex flex-col justify-between bg-gradient-to-b from-blue-500 to-orange-500">
      <div class="flex flex-col">
        <h1>Section 4 top</h1>
      </div>
      <div class="flex flex-col">
        <h1>Section 4 bottom</h1>
      </div>
    </div>
  </div>
</div>

React + Framer Motion方案

利用Framer Motion的滚动监听能力,添加平滑过渡动画,同时保留sticky布局逻辑:

import { motion, useScroll, useTransform } from "framer-motion";

export default function StickySectionDemo() {
  const { scrollYProgress } = useScroll();

  return (
    <div className="bg-black m-0 text-center text-white">
      {[1, 2, 3, 4].map((sectionNum) => {
        // 计算每个section的滚动触发区间
        const start = (sectionNum - 1) * 1.67;
        const end = sectionNum * 1.67;
        // 滚动到覆盖区域时,当前section逐渐淡出
        const opacity = useTransform(scrollYProgress, [start, start + 0.33], [1, 0]);

        return (
          <div key={sectionNum} className="h-[calc(100vh+67vh)]">
            <motion.div
              className="sticky top-0 min-h-screen flex flex-col justify-between bg-gradient-to-b from-blue-500 to-orange-500"
              style={{ opacity }}
              transition={{ duration: 0.3 }}
            >
              <div className="flex flex-col pt-8">
                <h1>Section {sectionNum} top</h1>
              </div>
              <div className="flex flex-col pb-8">
                <h1>Section {sectionNum} bottom</h1>
              </div>
            </motion.div>
          </div>
        );
      })}
    </div>
  );
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.26 12:15:57