如何实现网格布局侧边栏随相邻内容滚动后取消粘性定位?
问题
我用Grid布局做网页,想让左侧的侧边栏在对应行的内容滚到视图里时固定在页面顶部,当该行内容滚出屏幕后取消固定。现在已经给左侧div加了position: sticky和top: 0,单行的时候正常,但加了多行后多个侧边栏会重叠。我想要当前侧边栏在遇到下一个侧边栏到达顶部时自动脱离固定,请问这个效果能纯CSS实现吗,还是必须用JavaScript?
现有代码示例
CSS
.grid { display: grid; grid-template-columns: 25vw 75vw; grid-template-rows: auto auto; } .sidebar { border-right: 1px solid lightgray; border-left: 10px solid lightgray; max-height: 100vh; position: sticky; top: 0; } .content { flex-direction: column; max-width: 70vw; gap: 2em; }
HTML
<div class="grid"> <div class="sidebar"> <h1>我希望这个div在相邻行内容滚动时固定在屏幕顶部</h1> </div> <div class="content"> <h1>这里有大量内容</h1> <h1>高度撑满整个屏幕</h1> </div> <div class="sidebar"> <h1>但当该行到达顶部时,它会与第一个侧边栏重叠</h1> </div> <div class="content"> <h1>这里有大量内容</h1> <h1>高度撑满整个屏幕</h1> </div> </div>
解决方案
这个效果完全可以用纯CSS实现,不用JavaScript。核心是利用position: sticky的特性——粘性元素只会在其父容器的范围内保持固定,同时调整Grid结构,让每组侧边栏和对应内容处于同一个逻辑行,就能避免多个侧边栏重叠。
修改后的代码
CSS
.grid { display: grid; grid-template-columns: 25vw 75vw; grid-auto-rows: auto; } /* 用display: contents让行容器不占布局空间,只做逻辑分组 */ .grid-row { display: contents; } .sidebar { border-right: 1px solid lightgray; border-left: 10px solid lightgray; position: sticky; top: 0; align-self: start; /* 让侧边栏从行顶部开始定位 */ height: fit-content; /* 自适应内容高度 */ } .content { flex-direction: column; max-width: 70vw; gap: 2em; min-height: 100vh; /* 模拟长内容高度 */ }
HTML
<div class="grid"> <div class="grid-row"> <div class="sidebar"> <h1>这个div会在对应内容滚动时固定在顶部</h1> </div> <div class="content"> <h1>这里有大量内容</h1> <h1>高度撑满整个屏幕</h1> </div> </div> <div class="grid-row"> <div class="sidebar"> <h1>当我到达顶部时,上一个侧边栏会自动脱离</h1> </div> <div class="content"> <h1>这里有大量内容</h1> <h1>高度撑满整个屏幕</h1> </div> </div> </div>
原理说明
- 把每组
sidebar和content用grid-row包裹并设置display: contents,相当于让它们直接成为Grid的子元素,但保持逻辑分组。 - 每个侧边栏的
position: sticky只会在当前Grid行的范围内生效,当滚动到下一行时,当前侧边栏会因为超出了自身行的范围,自动取消固定并跟随内容滚动;而下一行的侧边栏会在到达顶部时固定,自然不会和上一个重叠。
内容的提问来源于stack exchange,提问作者phqshy
相关产品推荐
相关产品推荐

