循环文本缩放淡入淡出动画异常:首次循环后文本突兀显示
问题描述
我想要实现三个短语依次缩放淡入、淡出的无限循环动画,但首次循环完成后,文本会以100%不透明度突兀显示数秒,动画结束后突然消失;仅播放一次动画时无此异常。
原始代码
HTML
<div class="anim-box"> <h4 class="loop-phrase" id="move">Move Better</h4> <h4 class="loop-phrase" id="heal">Heal Faster</h4> <h4 class="loop-phrase" id="live">Live Longer</h4> </div>
CSS
.anim-box { display: flex; justify-content: center; align-items: center; height: 200px; } .loop-phrase { font-size: 24px; opacity: 0; position: absolute; color: #fff; } #move { animation: move 2s linear; } #heal { animation: heal 2s linear; animation-delay: 2s; } #live { animation: live 2s linear; animation-delay: 4s; } @keyframes move { 0% { transform: scale(1); opacity: 0; } 50% { transform: scale(2); opacity: 1; } 100% { transform: scale(1); opacity: 0; } } @keyframes heal { 0% { transform: scale(1); opacity: 0; } 50% { transform: scale(2); opacity: 1; } 100% { transform: scale(1); opacity: 0; } } @keyframes live { 0% { transform: scale(1); opacity: 0; } 50% { transform: scale(2); opacity: 1; } 100% { transform: scale(1); opacity: 0; } }
JavaScript
function animateText() { const moveText = document.getElementById('move'); const healText = document.getElementById('heal'); const liveText = document.getElementById('live'); let counter = 0; setInterval(() => { if (counter === 0) { moveText.style.opacity = 0; setTimeout(() => { moveText.style.opacity = 1; moveText.style.animation = 'none'; void moveText.offsetWidth; moveText.style.animation = 'move 2s linear'; counter++; }, 1000); } else if (counter === 1) { healText.style.opacity = 0; setTimeout(() => { healText.style.opacity = 1; healText.style.animation = 'none'; void healText.offsetWidth; healText.style.animation = 'heal 2s linear'; counter++; }, 1000); } else if (counter === 2) { liveText.style.opacity = 0; setTimeout(() => { liveText.style.opacity = 1; liveText.style.animation = 'none'; void liveText.offsetWidth; liveText.style.animation = 'live 2s linear'; counter = 0; }, 1000); } }, 3000); } window.onload = function() { animateText(); };
问题分析
- 手动opacity冲突:JS中手动设置
opacity:1会强制覆盖动画结束后的opacity:0状态,导致文本在间隔期突兀显示 - 定时器时间错位:
setInterval(3000)和内部setTimeout(1000)的时间组合,与动画时长(2秒)不匹配,导致循环衔接混乱
解决方案
推荐两种修复方式,优先选择纯CSS方案,更简洁稳定:
方案1:纯CSS实现无限循环(无JS)
直接通过CSS动画周期和延迟实现无缝循环,完全避免JS的时间控制问题:
.anim-box { display: flex; justify-content: center; align-items: center; height: 200px; } .loop-phrase { font-size: 24px; opacity: 0; position: absolute; color: #fff; /* 总周期6秒,对应3个元素各2秒动画 */ animation: scaleFadeLoop 6s linear infinite; } #move { animation-delay: 0s; } #heal { animation-delay: 2s; } #live { animation-delay: 4s; } @keyframes scaleFadeLoop { /* 0%、33.33%、100%状态保持透明,对应动画间隔 */ 0%, 33.33%, 100% { transform: scale(1); opacity: 0; } /* 16.66%为动画峰值,对应单个元素的淡入缩放顶点 */ 16.66% { transform: scale(2); opacity: 1; } }
方案2:优化JS逻辑(保留JS控制)
去掉手动opacity设置,让动画完全控制元素可见性,同时调整定时器时间匹配动画时长:
/* 先合并重复动画,减少冗余 */ .anim-box { display: flex; justify-content: center; align-items: center; height: 200px; } .loop-phrase { font-size: 24px; opacity: 0; position: absolute; color: #fff; } #move { animation: scaleFade 2s linear; } #heal { animation: scaleFade 2s linear; animation-delay: 2s; } #live { animation: scaleFade 2s linear; animation-delay: 4s; } @keyframes scaleFade { 0% { transform: scale(1); opacity: 0; } 50% { transform: scale(2); opacity: 1; } 100% { transform: scale(1); opacity: 0; } }
function animateText() { const phrases = [ document.getElementById('move'), document.getElementById('heal'), document.getElementById('live') ]; let currentIndex = 0; // 等待首次6秒初始动画完成后启动循环 setTimeout(() => { // 每2秒触发下一个元素的动画重置,匹配动画时长 setInterval(() => { const phrase = phrases[currentIndex]; // 重置动画状态 phrase.style.animation = 'none'; void phrase.offsetWidth; // 触发重绘,重置动画 phrase.style.animation = 'scaleFade 2s linear'; currentIndex = (currentIndex + 1) % phrases.length; }, 2000); }, 6000); } window.onload = animateText;
内容的提问来源于stack exchange,提问作者Ahmad
相关产品推荐
相关产品推荐

