求助:三列布局每列顶部区块仅在列内滚动固定的Vanilla JS实现
嘿,我来帮你搞定这个三列滚动时首区块固定的需求!结合你给出的原生JS代码片段,我给你完善出完整的实现方案,一步步来:
三列布局下首区块滚动固定实现(原生JS版)
第一步:先搭好基础HTML结构
先构建三列布局,每列的首个区块用.stick类标记,下面放足够多的内容来触发滚动效果:
<div class="container"> <div class="column"> <div class="stick">列1固定区块</div> <div class="content"> 列1内容<br>列1内容<br>列1内容<br>列1内容<br>列1内容<br> 列1内容<br>列1内容<br>列1内容<br>列1内容<br>列1内容<br> 列1内容<br>列1内容<br>列1内容<br>列1内容<br>列1内容<br> 列1内容<br>列1内容<br>列1内容<br>列1内容<br>列1内容<br> </div> </div> <div class="column"> <div class="stick">列2固定区块</div> <div class="content"> 列2内容<br>列2内容<br>列2内容<br>列2内容<br>列2内容<br> 列2内容<br>列2内容<br>列2内容<br>列2内容<br>列2内容<br> 列2内容<br>列2内容<br>列2内容<br>列2内容<br>列2内容<br> 列2内容<br>列2内容<br>列2内容<br>列2内容<br>列2内容<br> 列2内容<br>列2内容<br>列2内容<br>列2内容<br>列2内容<br> </div> </div> <div class="column"> <div class="stick">列3固定区块</div> <div class="content"> 列3内容<br>列3内容<br>列3内容<br>列3内容<br>列3内容<br> 列3内容<br>列3内容<br>列3内容<br>列3内容<br>列3内容<br> </div> </div> </div>
第二步:配置CSS样式
完成三列布局的基础样式,同时给固定状态的区块准备专属类,还要注意避免内容被固定区块遮挡:
.container { display: flex; gap: 20px; padding: 0 20px; } .column { flex: 1; position: relative; /* 核心:让固定区块相对于列定位 */ } .stick { background: #f0f0f0; padding: 15px; border: 1px solid #ddd; transition: position 0.2s ease; } /* 顶部固定状态 */ .stick.fixed { position: fixed; top: 0; width: calc(33.333% - 13.333px); /* 适配三列+gap的宽度,可根据布局调整 */ box-sizing: border-box; } /* 底部固定状态(滚动到列底部时) */ .stick.bottom-fixed { position: absolute; bottom: 0; top: auto; }
第三步:完整JavaScript逻辑(替代你现有的代码片段)
这段代码会处理每列的滚动判断,动态切换固定状态,而且做了性能优化(提前缓存尺寸数据):
document.addEventListener('DOMContentLoaded', function() { const sticks = document.querySelectorAll('.stick'); // 提前缓存每个固定区块的关联数据,避免滚动时重复计算 const stickData = Array.from(sticks).map(stick => { const column = stick.parentElement; return { stick, column, stickHeight: stick.offsetHeight, columnTop: column.offsetTop, columnBottom: column.offsetTop + column.offsetHeight }; }); function stickIt() { const scrollTop = window.pageYOffset || document.documentElement.scrollTop; stickData.forEach(data => { const { stick, column, stickHeight, columnTop, columnBottom } = data; // 计算两个关键滚动节点:开始固定的位置、切换到底部固定的位置 const shouldFixTop = scrollTop >= columnTop; const shouldFixBottom = scrollTop >= columnBottom - stickHeight; // 先移除所有状态类,避免样式冲突 stick.classList.remove('fixed', 'bottom-fixed'); if (shouldFixTop && !shouldFixBottom) { // 滚动到列范围内,固定在视口顶部 stick.classList.add('fixed'); column.style.paddingTop = `${stickHeight}px`; // 避免内容上移被遮挡 } else if (shouldFixBottom) { // 滚动到列底部区域,固定在列的底部 stick.classList.add('bottom-fixed'); column.style.paddingTop = '0'; } else { // 未滚动到列区域,恢复原样 column.style.paddingTop = '0'; } }); } // 绑定滚动事件 window.addEventListener('scroll', stickIt); // 页面加载时先执行一次,处理初始状态 stickIt(); });
核心逻辑说明
- 提前缓存每个
.stick对应的列尺寸、位置数据,减少滚动时的计算量,提升流畅度 - 滚动时根据
scrollTop判断当前处于哪个区间:- 滚动到列顶部下方 → 给区块添加
fixed类固定在视口顶部,同时给列加padding避免内容被遮挡 - 滚动到列底部上方(减去区块高度的位置)→ 切换到
bottom-fixed类,让区块固定在列的底部 - 滚动回列顶部上方 → 移除所有固定类,恢复列的原始样式
- 滚动到列顶部下方 → 给区块添加
小提示
- 固定区块的宽度要根据你的实际布局调整,比如三列带gap的情况,我用的
calc(33.333% - 13.333px)是分摊了gap的宽度,你可以根据自己的容器gap值修改 - 如果列的内容是动态加载的,记得在内容更新后重新计算
columnBottom和stickHeight这些数据,否则判断会出错
内容的提问来源于stack exchange,提问作者user3486427
相关产品推荐
相关产品推荐

