如何实现带自定义逻辑的弧形无限滚动跑马灯及视口背景切换
实现弧形无限跑马灯+中心触发背景切换
核心思路
- 弧形布局:通过CSS变换(
rotate+translate)让旗帜沿圆弧排列,模拟弧形轨道。 - 无缝滚动:复制一份旗帜列表,让两组列表连续滚动,当第一组完全移出视口时,第二组刚好接上,实现无限循环。
- 中心触发逻辑:实时检测每个旗帜的位置,当旗帜中心与视口中心重合时,切换背景色/背景图。
分步实现
1. HTML结构
<div class="bg-container"></div> <div class="marquee-container"> <div class="marquee-track"> <!-- 原始旗帜列表 --> <div class="flag" data-bg="#ff4444">旗帜1</div> <div class="flag" data-bg="#00C851">旗帜2</div> <div class="flag" data-bg="#33b5e5">旗帜3</div> <div class="flag" data-bg="#ffbb33">旗帜4</div> <!-- 复制一份用于无缝滚动 --> <div class="flag" data-bg="#ff4444">旗帜1</div> <div class="flag" data-bg="#00C851">旗帜2</div> <div class="flag" data-bg="#33b5e5">旗帜3</div> <div class="flag" data-bg="#ffbb33">旗帜4</div> </div> </div>
2. CSS布局
* { margin: 0; padding: 0; box-sizing: border-box; } .bg-container { position: fixed; top: 0; left: 0; width: 100vw; height: 100vh; background: #ff4444; transition: background 0.3s ease; z-index: 1; } .marquee-container { position: relative; width: 100vw; height: 400px; overflow: hidden; z-index: 2; margin-top: 200px; } .marquee-track { position: absolute; display: flex; gap: 80px; white-space: nowrap; } .flag { width: 120px; height: 180px; background: white; border-radius: 8px; display: flex; align-items: center; justify-content: center; font-weight: bold; box-shadow: 0 4px 12px rgba(0,0,0,0.15); }
3. GSAP动画与逻辑实现
// 初始化GSAP gsap.registerPlugin(ScrollTrigger); const track = document.querySelector('.marquee-track'); const flags = document.querySelectorAll('.flag'); const bgContainer = document.querySelector('.bg-container'); // 1. 将旗帜排列成弧形 const arcRadius = 300; // 弧形半径,可调整 const totalFlags = flags.length / 2; // 原始旗帜数量 flags.forEach((flag, index) => { // 计算每个旗帜的角度(只针对前半部分,复制的部分同步) const angle = (index % totalFlags) * (360 / totalFlags); // 旋转并沿圆弧定位 gsap.set(flag, { rotate: angle - 90, // 调整角度让旗帜朝向外侧 y: arcRadius * Math.cos((angle * Math.PI) / 180), x: arcRadius * Math.sin((angle * Math.PI) / 180), transformOrigin: 'center center' }); }); // 2. 创建无限滚动动画 const trackWidth = track.offsetWidth; gsap.to(track, { x: -trackWidth / 2, // 滚动距离为原始列表宽度 duration: 15, // 滚动时长,可调整 repeat: -1, // 无限循环 ease: 'linear' // 匀速滚动 }); // 3. 检测旗帜是否到达中心,切换背景 function checkFlagCenter() { const centerX = window.innerWidth / 2; flags.forEach(flag => { const flagRect = flag.getBoundingClientRect(); const flagCenterX = flagRect.left + flagRect.width / 2; // 允许±10px的误差范围 if (Math.abs(flagCenterX - centerX) < 10) { const targetBg = flag.dataset.bg; if (bgContainer.style.background !== targetBg) { bgContainer.style.background = targetBg; } } }); } // 每帧检测一次 gsap.ticker.add(checkFlagCenter);
关键细节说明
- 弧形调整:修改
arcRadius可以改变弧形的弧度大小,调整rotate值可以改变旗帜的朝向。 - 滚动速度:修改GSAP动画的
duration参数,数值越小滚动越快。 - 背景切换触发:通过
getBoundingClientRect()获取旗帜的实时位置,与视口中心对比,误差范围可以根据需求调整。 - 无缝滚动:复制原始旗帜列表是为了避免滚动到末尾出现空白,确保视觉上的无限循环。
内容的提问来源于stack exchange,提问作者Robin
相关产品推荐
相关产品推荐

