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

如何通过CSS实现滚动时多列持续可见的层级堆叠效果?

问题描述

我的网页包含三个"页面":红色页面、绿色页面和蓝色页面。每个页面均为sticky定位,尺寸为100vw×100vh。红色页面包含左侧列,绿色页面包含中间列,蓝色页面包含右侧列。滚动网页时,绿色页面会向上滑过红色页面,随后蓝色页面向上滑过绿色页面。

我想要实现的效果是:滚动绿色页面时左侧列保持可见,滚动蓝色页面时左侧和中间列保持可见,最终滚动至页面底部时,蓝色背景下三列全部可见。

我尝试通过提高column的z-index来实现,但理解这无效的原因是每个sticky div会创建独立的堆叠上下文。请问有人能告诉我如何用CSS实现该效果吗?如果不行我将改用JavaScript。


现有代码

CSS 代码

* {
    box-sizing: border-box;
}

body {
    height: 700vh;
    background-color: black;
}


.page {
    position: sticky;
    top: 0;

    width: 100vw;
    height: 100vh;

    padding: 5%;
}

#page1, #page4 {
    background-color: red;
}

#page2, #page5 {
    background-color: green;
}

#page3, #page6 {
    background-color: blue;
}

.column {
    float: left;
    width: 32.3%;
    height: 100%;

    margin-left: .5%;
    margin-right: .5%;

    background-color: #fffff4;

    position: relative;
    top: 0;
    z-index: 2;
}


#page1 :is(.column2, .column3) {
    visibility: hidden;
}

#page2 :is(.column1, .column3) {
    visibility: hidden;
}

#page3 :is(.column1, .column2) {
    visibility: hidden;
}

#explanation {
    color: white;
    background-color: black;
    font-size: 5vh;
}

#page4 :is(.column2, .column3) {
    visibility: hidden;
}

#page5 :is(.column3) {
    visibility: hidden;
}

HTML 代码

<div id="page1" class="page">
    <div class="column column1"></div>
    <div class="column column2"></div>
    <div class="column column3"></div>
</div>

<div id="page2" class="page">
    <div class="column column1"></div>
    <div class="column column2"></div>
    <div class="column column3"></div>
</div>

<div id="page3" class="page">
    <div class="column column1"></div>
    <div class="column column2"></div>
    <div class="column column3"></div>
</div>

<p id="explanation" class="page"> 后续3个页面展示了我想要实现的效果。请注意,在该示例中左侧列在第2、3页面被重复,中间列在第3页面被重复。我更希望不重复列而是让它们保持可见。另外我未提及列的最终内容,该代码片段是我最终要实现效果的简化版本。</p>

<div id="page4" class="page">
    <div class="column column1"></div>
    <div class="column column2"></div>
    <div class="column column3"></div>
</div>

<div id="page5" class="page">
    <div class="column column1"></div>
    <div class="column column2"></div>
    <div class="column column3"></div>
</div>

<div id="page6" class="page">
    <div class="column column1"></div>
    <div class="column column2"></div>
    <div class="column column3"></div>
</div>

解决方案

可以通过将列元素脱离各自的sticky页面容器,改为直接挂载在body下并使用position: fixed实现持久显示,同时配合sticky页面的背景层滑动效果。具体实现步骤如下:

1. 调整HTML结构

把三个列元素从各个page容器中抽离,放在所有页面元素之前,避免被sticky容器的堆叠上下文限制:

<!-- 抽离出来的固定列 -->
<div class="column column1"></div>
<div class="column column2"></div>
<div class="column column3"></div>

<!-- 原有的页面容器 -->
<div id="page1" class="page"></div>
<div id="page2" class="page"></div>
<div id="page3" class="page"></div>
<p id="explanation" class="page"> 后续3个页面展示了我想要实现的效果。请注意,在该示例中左侧列在第2、3页面被重复,中间列在第3页面被重复。我更希望不重复列而是让它们保持可见。另外我未提及列的最终内容,该代码片段是我最终要实现效果的简化版本。</p>
<div id="page4" class="page"></div>
<div id="page5" class="page"></div>
<div id="page6" class="page"></div>

2. 修改CSS样式

  • 让列元素固定定位,设置好位置和层级,确保在页面背景之上
  • 利用:has()选择器根据当前sticky页面的状态控制列的显示
  • 调整原页面容器的层级,让背景在列下方
* {
    box-sizing: border-box;
}

body {
    height: 700vh;
    background-color: black;
}

/* 固定列样式 */
.column {
    position: fixed;
    top: 5%; /* 与page的padding值保持一致 */
    bottom: 5%;
    width: 32.3%;
    margin-left: .5%;
    margin-right: .5%;
    background-color: #fffff4;
    z-index: 2;
    opacity: 0; /* 默认隐藏,通过滚动阶段控制显示 */
    transition: opacity 0.1s ease; /* 可选过渡效果,让显示更平滑 */
}

/* 定位三个列的位置 */
.column1 { left: 5%; }
.column2 { left: calc(5% + 33.3%); } /* 5% padding + 32.3%宽度 + 1%左右margin */
.column3 { left: calc(5% + 66.6%); }

/* 根据sticky页面状态控制列显示 */
/* 滚动过红色页面后,显示左侧列 */
body:not(:has(#page1:sticky)) .column1 { opacity: 1; }
/* 滚动过绿色页面后,显示中间列 */
body:not(:has(#page1:sticky):has(#page2:sticky)) .column2 { opacity: 1; }
/* 滚动到蓝色页面后,显示右侧列 */
body:not(:has(#page1:sticky):has(#page2:sticky):has(#page3:sticky)) .column3 { opacity: 1; }

/* 页面容器样式调整 */
.page {
    position: sticky;
    top: 0;
    width: 100vw;
    height: 100vh;
    padding: 5%;
    z-index: 1; /* 让页面背景在列的下方 */
}

#page1, #page4 {
    background-color: red;
}

#page2, #page5 {
    background-color: green;
}

#page3, #page6 {
    background-color: blue;
}

#explanation {
    color: white;
    background-color: black;
    font-size: 5vh;
}

兼容性说明

如果浏览器不支持:has()选择器(如旧版Firefox),可以用以下两种方式降级:

  1. 使用JavaScript监听滚动事件,通过判断页面的sticky状态来切换列的opacity类
  2. 利用滚动触发的CSS变量,结合scroll-snap实现类似效果

这种方案彻底避开了sticky容器的堆叠上下文问题,让列元素独立于页面层之上,完美实现滚动时逐步显示、最终三列全显的效果。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.08 05:44:56