滚动触发动画前文本区块提前显示的修复需求
修复滚动触发文本动画的Bug
核心问题分析
你遇到的问题是两个原因叠加导致的:
- CSS动画未设置保持结束状态,动画跑完后元素又回到初始
opacity: 0 - 滚动监听逻辑过于灵敏,慢滚动时频繁触发类的添加/移除,导致元素反复显示消失
第一步:修复CSS动画逻辑
先确保动画结束后能保持显示状态,同时避免初始样式和动画的优先级冲突:
/* 初始隐藏状态 */ .target-text-block { opacity: 0; /* 可选:加过渡防止切换时闪烁 */ transition: opacity 0.2s ease; } /* 定义淡入关键帧 */ @keyframes fadeInText { 0% { opacity: 0; transform: translateY(10px); } 100% { opacity: 1; transform: translateY(0); } } /* 动画触发类 - 用组合选择器提高优先级 */ .target-text-block.animate-text { /* forwards 是核心:让动画结束后停在最后一帧 */ animation: fadeInText 0.6s ease-out forwards; }
第二步:用Intersection Observer替代滚动监听
传统scroll事件监听容易因频繁触发导致类反复切换,浏览器原生的Intersection Observer能精准判断元素是否进入视口,稳定性更高:
// 获取所有需要动画的文本区块 const textBlocks = document.querySelectorAll('.target-text-block'); // 创建观察器实例 const observer = new IntersectionObserver((entries) => { entries.forEach(entry => { // 元素进入视口时添加动画类 if (entry.isIntersecting) { entry.target.classList.add('animate-text'); // 只触发一次动画,添加后停止观察该元素 observer.unobserve(entry.target); } }); }, { // 元素10%进入视口时触发动画(可自行调整阈值) threshold: 0.1, // 可选:调整触发时机,比如元素底部距视口底部50px时触发 rootMargin: '0px 0px -50px 0px' }); // 开始观察每个文本区块 textBlocks.forEach(block => observer.observe(block));
如果必须保留滚动监听(不推荐)
一定要加节流函数限制触发频率,同时确保每个元素只添加一次动画类:
// 节流函数:控制事件触发频率 function throttle(func, delay = 100) { let lastRun = 0; return function(...args) { const now = Date.now(); if (now - lastRun >= delay) { lastRun = now; func.apply(this, args); } }; } // 滚动监听逻辑 window.addEventListener('scroll', throttle(() => { textBlocks.forEach(block => { const rect = block.getBoundingClientRect(); // 判断元素是否进入视口 const isVisible = rect.top < window.innerHeight && rect.bottom > 0; // 只添加一次类,避免反复切换 if (isVisible && !block.classList.contains('animate-text')) { block.classList.add('animate-text'); } }); }));
关键注意事项
- 必须给动画类加上
animation-fill-mode: forwards,否则动画结束后元素会回到初始隐藏状态 - 优先使用Intersection Observer替代
scroll事件监听,避免频繁触发导致的异常 - 不要反复添加/移除动画类,确保每个元素只触发一次动画
内容的提问来源于stack exchange,提问作者Sam S
相关产品推荐
相关产品推荐

