使用jQuery实现Marquee:循环重启时动画卡顿问题求助
解决无限循环Marquee动画卡顿问题
我正在实现一个100%宽度、从右向左无限循环的Marquee组件,初始仅包含一个元素。需要计算填充容器所需的元素数量,确保循环结束与文本开头之间无间隙,但当前实现中循环重启时动画出现卡顿,如何解决?
原实现代码
HTML
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script> <div class="marquee-container"> <div class="marquee-content"> <span>All words and no speaking, makes us all write.</span> </div> </div>
CSS
.marquee-container { width: 100%; overflow: hidden; position: relative; height: 50px; } .marquee-content { display: flex; white-space: nowrap; position: absolute; animation: marqueeAnimation 4s linear infinite; } .marquee-content span { display: inline-block; margin-right: 20px; /* Adjust as needed */ } @keyframes marqueeAnimation { 0% { transform: translateX(0%); } 100% { transform: translateX(calc(-100% + 100vw)); } }
JavaScript
$(document).ready(function() { function calculateElements() { const containerWidth = $('.marquee-container').width(); const elementWidth = $('.marquee-content span').outerWidth(true); const numElements = Math.ceil(containerWidth / elementWidth) + 3; for (let i = 1; i < numElements; i++) { $('.marquee-content').append($('.marquee-content span:first').clone()); } } calculateElements(); });
卡顿原因与修复方案
卡顿核心原因
动画结束时的位移位置和起始位置无法无缝衔接,导致动画重置时出现跳变断层;同时元素数量计算逻辑冗余,没有精准匹配循环衔接的需求。
具体修复步骤
精准计算需要克隆的元素数量
总内容宽度需要至少覆盖容器宽度 + 单个元素宽度,这样滚动时最后一个元素的末端能和第一个元素的起始在容器内衔接,公式调整为:const numElements = Math.ceil(containerWidth / elementWidth) + 1;修正动画关键帧逻辑
动画结束位置应该设置为-单个元素的宽度,而不是calc(-100% + 100vw)。这样当动画循环时,内容刚好向左移动了一个元素的宽度,视觉上完全衔接:@keyframes marqueeAnimation { 0% { transform: translateX(0); } 100% { transform: translateX(-var(--element-width)); } }通过CSS变量
--element-width动态传入单个元素的宽度,保证精准性。开启硬件加速优化性能
在.marquee-content中添加will-change: transform,让浏览器提前为动画分配GPU资源,减少卡顿:.marquee-content { /* 原有样式 */ will-change: transform; /* 开启硬件加速 */ }优化DOM克隆逻辑
缓存第一个元素的克隆对象,避免重复查询DOM,提升初始化性能。
修改后的完整代码
HTML
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script> <div class="marquee-container"> <div class="marquee-content"> <span>All words and no speaking, makes us all write.</span> </div> </div>
CSS
.marquee-container { width: 100%; overflow: hidden; position: relative; height: 50px; } .marquee-content { display: flex; white-space: nowrap; position: absolute; animation: marqueeAnimation 4s linear infinite; will-change: transform; } .marquee-content span { display: inline-block; margin-right: 20px; } @keyframes marqueeAnimation { 0% { transform: translateX(0); } 100% { transform: translateX(-var(--element-width)); } }
JavaScript
$(document).ready(function() { function calculateElements() { const $container = $('.marquee-container'); const $content = $('.marquee-content'); const $firstSpan = $content.find('span:first'); const containerWidth = $container.width(); const elementWidth = $firstSpan.outerWidth(true); const numElements = Math.ceil(containerWidth / elementWidth) + 1; const $clone = $firstSpan.clone(); $content.css('--element-width', `${elementWidth}px`); for (let i = 1; i < numElements; i++) { $content.append($clone.clone()); } } calculateElements(); });
内容的提问来源于stack exchange,提问作者8BitSigdom
相关产品推荐
相关产品推荐

