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

如何实现滚动时顶部固定div被下方div顶出的效果(仿Telegram日期栏)

实现Telegram式聊天日期栏效果的方案

能不能只用CSS实现?

不行。CSS的position: sticky只能让单个元素在容器内固定,当新的日期栏滚动到顶部时,会直接覆盖在旧日期栏上方,做不到“顶出”的平移过渡效果,必须结合JavaScript来控制元素的位置和动画逻辑。

具体实现方案(含JS示例)

核心思路是监听滚动事件,实时判断每个日期栏的位置:当旧日期栏固定在顶部时,新日期栏接近顶部时,让旧日期栏向上滑出视口,同时将新日期栏固定到顶部;向上滚动时则恢复上一个日期栏的固定状态。

以下是完整示例代码:

HTML结构

<div class="chat-container">
  <!-- 4月18日聊天组 -->
  <div class="date-divider" data-date="4月18日">4月18日</div>
  <div class="chat-message">今天天气不错</div>
  <div class="chat-message">要不要一起吃饭?</div>
  
  <!-- 4月16日聊天组 -->
  <div class="date-divider" data-date="4月16日">4月16日</div>
  <div class="chat-message">昨天的会议记录发我一下</div>
  <div class="chat-message">好的,马上发你</div>
  
  <!-- 4月15日聊天组 -->
  <div class="date-divider" data-date="4月15日">4月15日</div>
  <div class="chat-message">周末打算去哪玩?</div>
  <div class="chat-message">还没想好,你有推荐吗?</div>
  <div class="chat-message">可以去郊外露营,挺不错的</div>
  
  <!-- 4月14日聊天组 -->
  <div class="date-divider" data-date="4月14日">4月14日</div>
  <div class="chat-message">今天加班到很晚</div>
  <div class="chat-message">注意休息,别太累了</div>
</div>

CSS样式

.chat-container {
  max-width: 400px;
  margin: 0 auto;
  padding: 20px 0;
  height: 500px;
  overflow-y: auto;
  border: 1px solid #eee;
}

.date-divider {
  text-align: center;
  padding: 8px 0;
  background: #f5f5f5;
  color: #666;
  margin: 10px 0;
  border-radius: 4px;
  position: relative;
  transition: transform 0.3s ease;
  z-index: 10;
}

.date-divider.fixed {
  position: fixed;
  top: 0;
  left: 50%;
  transform: translateX(-50%);
  width: 400px;
  margin: 0;
}

.chat-message {
  padding: 10px 15px;
  margin: 5px 0;
  background: #e5e5ea;
  border-radius: 18px;
  max-width: 70%;
  margin-left: auto;
}

JavaScript逻辑

const chatContainer = document.querySelector('.chat-container');
const dateDividers = document.querySelectorAll('.date-divider');
let currentFixedDivider = null;

chatContainer.addEventListener('scroll', () => {
  const containerTop = chatContainer.getBoundingClientRect().top;
  
  dateDividers.forEach(divider => {
    const rect = divider.getBoundingClientRect();
    // 计算日期栏相对于容器顶部的位置
    const relativeTop = rect.top - containerTop;
    
    // 当日期栏即将滚动到容器顶部时
    if (relativeTop <= 0 && !divider.classList.contains('fixed')) {
      if (currentFixedDivider) {
        // 让当前固定的日期栏向上滑出视口
        const slideOutDistance = currentFixedDivider.offsetHeight;
        currentFixedDivider.style.transform = `translateX(-50%) translateY(-${slideOutDistance}px)`;
        // 动画结束后清除固定状态
        setTimeout(() => {
          currentFixedDivider.classList.remove('fixed');
          currentFixedDivider.style.transform = '';
        }, 300);
      }
      // 固定当前日期栏到顶部
      divider.classList.add('fixed');
      currentFixedDivider = divider;
    }
    
    // 向上滚动时,恢复上一个日期栏的固定状态
    if (relativeTop > divider.offsetHeight && divider.classList.contains('fixed')) {
      divider.classList.remove('fixed');
      const prevDivider = divider.previousElementSibling?.closest('.date-divider');
      if (prevDivider) {
        prevDivider.classList.add('fixed');
        currentFixedDivider = prevDivider;
      } else {
        currentFixedDivider = null;
      }
    }
  });
});

// 初始化时触发一次滚动检查
chatContainer.dispatchEvent(new Event('scroll'));

效果说明

  • 向下滚动查看旧消息时,当前日期栏会固定在容器顶部;
  • 新日期栏滚动到容器顶部时,旧日期栏会平滑向上滑出,新日期栏随即固定到顶部;
  • 向上滚动时,会自动恢复上一个日期栏的固定状态。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.01 23:25:25