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

求助:三列布局每列顶部区块仅在列内滚动固定的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判断当前处于哪个区间:
    1. 滚动到列顶部下方 → 给区块添加fixed类固定在视口顶部,同时给列加padding避免内容被遮挡
    2. 滚动到列底部上方(减去区块高度的位置)→ 切换到bottom-fixed类,让区块固定在列的底部
    3. 滚动回列顶部上方 → 移除所有固定类,恢复列的原始样式

小提示

  • 固定区块的宽度要根据你的实际布局调整,比如三列带gap的情况,我用的calc(33.333% - 13.333px)是分摊了gap的宽度,你可以根据自己的容器gap值修改
  • 如果列的内容是动态加载的,记得在内容更新后重新计算columnBottom和stickHeight这些数据,否则判断会出错

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.22 08:03:14