如何在元素进入视口时触发webkit文本高亮动画?
解决方案
步骤1:调整CSS,分离动画触发逻辑
把原本直接绑定在mark元素上的动画属性移到独立CSS类中,默认状态下不触发动画,仅当元素进入视口时通过JS添加类来启动动画:
mark { background-color: transparent; background: linear-gradient(90deg, #C7A4D8 50%, rgba(255, 255, 255, 0) 50%); background-size: 200% 100%; background-position: 100% 0; } /* 动画触发类 */ mark.highlight-active { -webkit-animation: 1s highlight 1s 1 normal forwards; animation: 1s highlight 1s 1 normal forwards; } @-webkit-keyframes highlight { to { background-position: 0 0; } } @keyframes highlight { to { background-position: 0 0; } }
步骤2:纯JS实现视口检测与动画触发
方案一:滚动监听(新手易理解)
这段代码监听页面滚动,判断元素是否进入视口,一旦进入就添加触发类,且仅执行一次:
const highlightElement = document.querySelector('mark'); let animationTriggered = false; // 判断元素是否在视口内 function isElementInViewport(el) { const rect = el.getBoundingClientRect(); return ( rect.top >= 0 && rect.left >= 0 && rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) && rect.right <= (window.innerWidth || document.documentElement.clientWidth) ); } // 滚动时检查元素状态 function checkScroll() { if (!animationTriggered && isElementInViewport(highlightElement)) { highlightElement.classList.add('highlight-active'); animationTriggered = true; // 触发后移除监听,优化性能 window.removeEventListener('scroll', checkScroll); } } // 初始化时先检查一次(防止元素一开始就在视口内) checkScroll(); window.addEventListener('scroll', checkScroll);
方案二:Intersection Observer(性能更优)
使用浏览器原生API,避免滚动事件频繁触发的性能损耗,代码更简洁:
const highlightElement = document.querySelector('mark'); const observer = new IntersectionObserver((entries) => { entries.forEach(entry => { if (entry.isIntersecting) { entry.target.classList.add('highlight-active'); // 触发后停止监听 observer.unobserve(entry.target); } }); }); observer.observe(highlightElement);
说明
- 两种方案均为纯JS实现,无额外依赖,不影响页面加载速度。
- CSS分离了元素基础样式和动画触发逻辑,更易维护。
- 两种方案都确保动画仅触发一次,避免重复执行。
内容的提问来源于stack exchange,提问作者shoobydoo
相关产品推荐
相关产品推荐

