如何实现元素横向滑出页面后从左侧重新进入的循环动画?
问题分析
你的代码无法实现预期滑动循环效果的核心原因:
- 仅定义了单个动画关键帧,浏览器默认以元素初始状态为起始帧,动画仅执行「从初始位置移动到
translateX(300px)」这一段,随后直接跳回初始位置循环,完全没有滑出页面再从左侧进入的完整逻辑。 - 未处理初始处于容器右侧外的元素的入场逻辑,也未定义元素滑出后重置位置的路径。
解决方案:用CSS动画实现连贯循环(性能更优)
通过CSS定义完整滑动路径,同时为元素设置递增延迟,形成连贯滚动效果,还能处理初始视图外元素的入场:
<div class="container"> <div class="child">1</div> <div class="child">2</div> <div class="child">3</div> <div class="child">4</div> <div class="child">5</div> <div class="child">6</div> <div class="child">7</div> <div class="child">8</div> </div>
.container { background-color: aqua; width: 1000px; display: flex; flex-direction: row; overflow: hidden; padding: 20px 0; gap: 10px; } .child { background-color: red; flex: 0 0 20%; height: 100px; display: flex; align-items: center; justify-content: center; color: white; font-size: 20px; /* 初始状态:右侧溢出元素先定位到容器左侧外 */ transform: translateX(calc(-100% - 10px)); animation: slideLoop 8s linear infinite; } /* 为每个元素设置递增延迟,形成连贯滑动 */ .child:nth-child(1) { animation-delay: 0s; transform: translateX(0); } .child:nth-child(2) { animation-delay: 1s; transform: translateX(0); } .child:nth-child(3) { animation-delay: 2s; transform: translateX(0); } .child:nth-child(4) { animation-delay: 3s; transform: translateX(0); } .child:nth-child(5) { animation-delay: 4s; } .child:nth-child(6) { animation-delay: 5s; } .child:nth-child(7) { animation-delay: 6s; } .child:nth-child(8) { animation-delay: 7s; } /* 完整滑动循环动画 */ @keyframes slideLoop { 0% { transform: translateX(0); /* 元素在容器内的初始位置 */ } 90% { transform: translateX(calc(1000px + 100%)); /* 向右滑出容器(1000px为容器宽度,确保完全移出) */ } 90.1% { transform: translateX(calc(-100% - 10px)); /* 瞬间跳到容器左侧外 */ } 100% { transform: translateX(0); /* 回到容器内,准备下一次循环 */ } }
方案说明
- 初始状态处理:右侧溢出的元素默认定位在容器左侧外,通过动画延迟依次进入视图。
- 动画路径:
slideLoop关键帧定义了「容器内停留→向右滑出→左侧外重置→回到容器内」的完整循环。 - 延迟设置:递增的动画延迟让元素滑动错落有致,避免整体生硬移动。
若坚持使用JS动画修正
如果更倾向于JS实现,需要定义完整关键帧序列,并处理元素初始位置:
const elems = document.getElementsByClassName("child"); const containerWidth = document.querySelector('.container').offsetWidth; Array.from(elems).forEach((elem, index) => { // 先把右侧溢出的元素移到容器内初始位置 if (index >= 4) { elem.style.transform = `translateX(${-(index - 4) * (elem.offsetWidth + 10)}px)`; } elem.animate( [ { transform: elem.style.transform || "translateX(0)" }, { transform: `translateX(${containerWidth + elem.offsetWidth}px)` }, // 滑出右侧 { transform: `translateX(-${elem.offsetWidth + 10}px)`, offset: 0.9 }, // 跳到左侧外 { transform: elem.style.transform || "translateX(0)" } // 回到初始位置 ], { duration: 8000, iterations: Infinity, delay: index * 1000, easing: 'linear' } ); });
.container { background-color: aqua; width: 1000px; display: flex; flex-direction: row; overflow:hidden; padding: 20px 0; gap: 10px; } .child { background-color: red; flex: 0 0 20%; height: 100px; display: flex; align-items: center; justify-content: center; color: white; font-size: 20px; }
内容的提问来源于stack exchange,提问作者user7167081
相关产品推荐
相关产品推荐

