如何实现文本无缝循环滚动?附现有代码求解决方案
实现文本无缝循环滚动的方案
核心思路
- 复制一份滚动内容,让原内容与复制内容首尾相连,形成连续的“循环体”
- 当滚动容器向上滚动完原内容的高度时,瞬间将容器位置重置到初始状态,由于复制内容和原内容完全一致,视觉上不会出现空白间隙
- 用JavaScript控制滚动逻辑,适配动态内容高度,比纯CSS方案更灵活
修改后的完整代码
HTML
<div id="jobs_container"> <div id="jobs_header"> <div id="jobs_header_left"></div> <div id="jobs_header_center">Center text</div> <div id="jobs_header_right"></div> </div> <div id="jobs_content"> <div id="jobs_listOfEvents"> line1<hr> line2<hr> line3<hr> line4<hr> line5<hr> line6<hr> line7<hr> line8<hr> line9<hr> </div> <!-- 复制一份内容用于无缝衔接 --> <div id="jobs_listOfEvents_copy"></div> </div> </div>
CSS
#jobs_container { background: transparent; width: 600px; height: 300px; border: 3px solid #e4e4e4; border-radius: 12px; border-style: dashed; padding: 1px; font-size: 12px; } #jobs_header { display: flex; justify-content: space-between; height: 25px; background-color: #e4e4e4; border-radius: 12px 12px 0 0; padding: 1rem; } #jobs_header_left { display: flex; align-items: center; } #jobs_header_left > span { padding-right: 4px; cursor: pointer; color: #0048FF; } #jobs_header_center { text-align: center; font: 20px Verdana; color: darkblue; } #jobs_header_right { display: flex; align-items: center; } #jobs_today { margin-inline: 5px; cursor: pointer; color: #0048FF; } #jobs_nextButton { background: transparent; border: none; padding: 0px 3px; cursor: pointer; } #jobs_prevButton { background: transparent; border: none; transform: scaleX(-1); padding: 0px 3px; cursor: pointer; } #jobs_content { font-family: calibre; margin-left: 10px; margin-top: 10px; position: relative; overflow: hidden; /* 只显示容器范围内的内容 */ max-height: 220px; /* 减去header高度,避免超出容器 */ text-align: justify; } #jobs_listOfEvents, #jobs_listOfEvents_copy { position: relative; }
JavaScript
const originalList = document.getElementById('jobs_listOfEvents'); const copyList = document.getElementById('jobs_listOfEvents_copy'); // 复制原内容到副本 copyList.innerHTML = originalList.innerHTML; const contentContainer = document.getElementById('jobs_content'); const itemHeight = originalList.offsetHeight; // 创建滚动动画 function startScroll() { // 重置初始位置 originalList.style.top = '0px'; copyList.style.top = `${itemHeight}px`; let scrollPosition = 0; const scrollSpeed = 0.5; // 滚动速度,数值越小越慢 let requestId; function animateScroll() { scrollPosition += scrollSpeed; originalList.style.top = `-${scrollPosition}px`; copyList.style.top = `${itemHeight - scrollPosition}px`; // 当滚动完原内容高度时,重置位置实现无缝衔接 if (scrollPosition >= itemHeight) { scrollPosition = 0; } requestId = requestAnimationFrame(animateScroll); } requestId = requestAnimationFrame(animateScroll); // 鼠标悬停暂停滚动,离开继续 contentContainer.addEventListener('mouseenter', () => { cancelAnimationFrame(requestId); }); contentContainer.addEventListener('mouseleave', () => { requestId = requestAnimationFrame(animateScroll); }); } // 页面加载完成后启动滚动 window.addEventListener('load', startScroll);
关键逻辑说明
- 内容复制:将原滚动内容复制一份,放在原内容下方,形成连续的内容流
- 滚动控制:用
requestAnimationFrame实现平滑向上滚动,同步控制原内容和副本的位置 - 无缝重置:当滚动距离等于原内容高度时,立即重置滚动位置,此时副本顶部刚好衔接原内容底部,视觉上无间隙
- 交互优化:添加鼠标悬停暂停滚动的功能,提升用户体验
内容的提问来源于stack exchange,提问作者Jack
相关产品推荐
相关产品推荐

