解决Vanilla JS跑马灯效果中SVG抖动问题
解决原生JS跑马灯中SVG/图片抖动问题
我用原生JavaScript实现了跑马灯效果,功能正常,但SVG(及图片)在移动时出现抖动现象。以下是原实现代码:
<div class="marquee"> <h1>Nepal <svg version="1.1" viewBox="0 0 36 31" xmlns="http://www.w3.org/2000/svg"><path d="M8.80476 8.17844V12.3988H3.9993V4.25693H8.79846V8.17844H8.80476ZM32.4101 3.87271V0H20.0028V3.87271H16.0035V0H3.60252V3.87271H0V15.497H3.60252V19.76H7.60182V23.2485H11.6011V27.5115H15.6004V31H20.3996V27.5115H24.3989V23.2485H28.3982V19.76H32.3975V15.497H36V3.87271" fill="#DA2269"/></svg> Himalayas <svg version="1.1" viewBox="0 0 36 31" xmlns="http://www.w3.org/2000/svg"><path d="M8.80476 8.17844V12.3988H3.9993V4.25693H8.79846V8.17844H8.80476ZM32.4101 3.87271V0H20.0028V3.87271H16.0035V0H3.60252V3.87271H0V15.497H3.60252V19.76H7.60182V23.2485H11.6011V27.5115H15.6004V31H20.3996V27.5115H24.3989V23.2485H28.3982V19.76H32.3975V15.497H36V3.87271" fill="#DA2269"/></svg> Mountains <svg version="1.1" viewBox="0 0 36 31" xmlns="http://www.w3.org/2000/svg"><path d="M8.80476 8.17844V12.3988H3.9993V4.25693H8.79846V8.17844H8.80476ZM32.4101 3.87271V0H20.0028V3.87271H16.0035V0H3.60252V3.87271H0V15.497H3.60252V19.76H7.60182V23.2485H11.6011V27.5115H15.6004V31H20.3996V27.5115H24.3989V23.2485H28.3982V19.76H32.3975V15.497H36V3.87271" fill="#DA2269"/></svg> Everest</h1> </div> <style> .marquee { overflow: hidden; border-top: 1px solid #000; border-bottom: 1px solid #000; display: flex; } .marquee h1{ font-size: 5em; white-space: nowrap; text-transform: uppercase } .marquee h1 svg { width: auto; height: 60px; } </style> <script> function Marquee(selector, speed) { const parentSelector = document.querySelector(selector); const clone = parentSelector.innerHTML; const firstElement = parentSelector.children[0]; let i = 0; console.log(firstElement); parentSelector.insertAdjacentHTML('beforeend', clone); parentSelector.insertAdjacentHTML('beforeend', clone); setInterval(function () { firstElement.style.marginLeft = `-${i}px`; if (i > firstElement.clientWidth) { i = 0; } i = i + speed; }, 0); } window.addEventListener('load', () => Marquee('.marquee', 0.2)) </script>
解决抖动的核心方案
抖动主要源于margin-left触发的频繁重排、setInterval和浏览器刷新不同步,以及亚像素渲染问题,可通过以下几点修复:
- 用
transform: translateX()替代margin-left:transform属性由GPU加速处理,不会触发页面重排,动画更平滑。 - 替换
setInterval为requestAnimationFrame:该API会和浏览器的刷新频率(通常60Hz)同步执行,避免丢帧导致的抖动。 - 添加渲染优化提示:给运动元素添加
will-change: transform,让浏览器提前分配资源优化渲染。 - 优化SVG渲染:给SVG添加
shape-rendering: crispEdges,避免亚像素渲染导致的模糊抖动。
修改后的完整代码
<div class="marquee"> <h1>Nepal <svg version="1.1" viewBox="0 0 36 31" xmlns="http://www.w3.org/2000/svg"><path d="M8.80476 8.17844V12.3988H3.9993V4.25693H8.79846V8.17844H8.80476ZM32.4101 3.87271V0H20.0028V3.87271H16.0035V0H3.60252V3.87271H0V15.497H3.60252V19.76H7.60182V23.2485H11.6011V27.5115H15.6004V31H20.3996V27.5115H24.3989V23.2485H28.3982V19.76H32.3975V15.497H36V3.87271" fill="#DA2269"/></svg> Himalayas <svg version="1.1" viewBox="0 0 36 31" xmlns="http://www.w3.org/2000/svg"><path d="M8.80476 8.17844V12.3988H3.9993V4.25693H8.79846V8.17844H8.80476ZM32.4101 3.87271V0H20.0028V3.87271H16.0035V0H3.60252V3.87271H0V15.497H3.60252V19.76H7.60182V23.2485H11.6011V27.5115H15.6004V31H20.3996V27.5115H24.3989V23.2485H28.3982V19.76H32.3975V15.497H36V3.87271" fill="#DA2269"/></svg> Mountains <svg version="1.1" viewBox="0 0 36 31" xmlns="http://www.w3.org/2000/svg"><path d="M8.80476 8.17844V12.3988H3.9993V4.25693H8.79846V8.17844H8.80476ZM32.4101 3.87271V0H20.0028V3.87271H16.0035V0H3.60252V3.87271H0V15.497H3.60252V19.76H7.60182V23.2485H11.6011V27.5115H15.6004V31H20.3996V27.5115H24.3989V23.2485H28.3982V19.76H32.3975V15.497H36V3.87271" fill="#DA2269"/></svg> Everest</h1> </div> <style> .marquee { overflow: hidden; border-top: 1px solid #000; border-bottom: 1px solid #000; display: flex; } .marquee h1{ font-size: 5em; white-space: nowrap; text-transform: uppercase; will-change: transform; /* 提前告知浏览器元素将变换 */ } .marquee h1 svg { width: auto; height: 60px; shape-rendering: crispEdges; /* 优化SVG渲染,避免亚像素模糊 */ } </style> <script> function Marquee(selector, speed) { const parentSelector = document.querySelector(selector); const clone = parentSelector.innerHTML; const firstElement = parentSelector.children[0]; let position = 0; parentSelector.insertAdjacentHTML('beforeend', clone); parentSelector.insertAdjacentHTML('beforeend', clone); function animate() { position += speed; // 当元素完全移出左侧时重置位置 if (position >= firstElement.clientWidth) { position = 0; } // 使用transform实现平移 firstElement.style.transform = `translateX(-${position}px)`; requestAnimationFrame(animate); } requestAnimationFrame(animate); } window.addEventListener('load', () => Marquee('.marquee', 0.2)) </script>
内容的提问来源于stack exchange,提问作者Diego Somar
相关产品推荐
相关产品推荐

