如何通过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),可以用以下两种方式降级:
- 使用JavaScript监听滚动事件,通过判断页面的sticky状态来切换列的
opacity类 - 利用滚动触发的CSS变量,结合
scroll-snap实现类似效果
这种方案彻底避开了sticky容器的堆叠上下文问题,让列元素独立于页面层之上,完美实现滚动时逐步显示、最终三列全显的效果。
内容的提问来源于stack exchange,提问作者Verticon
相关产品推荐
相关产品推荐

