如何让CSS入场动画延迟到元素进入视口后再触发
问题解答
能否纯CSS实现?
不能。目前CSS没有提供检测元素是否进入视口的原生能力,所有滚动触发动画的通用场景都需要配合少量JavaScript实现。网传的:target伪类、锚点跳转等方案仅适配URL跳转到对应元素的特殊场景,无法覆盖用户自然滚动触发的需求。
最优实现方案
推荐使用浏览器原生的Intersection Observer API实现,相比传统监听scroll事件+计算元素位置的方案,性能更好,不会频繁触发回调导致页面卡顿,现代浏览器兼容性覆盖98%以上的用户。
第一步:修改CSS逻辑
不要直接给#time span绑定动画,默认只保留元素的初始隐藏状态,等元素进入视口、添加标记类后再触发动画,调整后的CSS代码如下:
#time span { opacity: 0; transform: translateY(30px); display: inline-block; } /* 元素进入视口添加in-view类后,才启动逐词动画 */ #time.in-view span { animation: time 0.5s ease-out forwards; } #time.in-view span:nth-of-type(2) { animation-delay: 0.2s; } #time.in-view span:nth-of-type(3) { animation-delay: 0.4s; } #time.in-view span:nth-of-type(4) { animation-delay: 0.6s; } @keyframes time { to { opacity: 1; transform: translateY(0); } }
注:上述代码里的动画延迟间隔调整为了0.2s逐次错开,如果你需要保持原来的间隔节奏,把delay值改回你原来的0.5s、1s即可。
第二步:补充JavaScript视口检测逻辑
保留你原有的时段问候逻辑,新增视口观察代码即可:
const timeEl = document.getElementById("time"); // 原有时段判断逻辑 const time = new Date().getHours(); if (time >= 1 && time <= 12) { timeEl.innerHTML = "<span>☀️</span> <span>Good</span> <span>Morning,</span> <span>Creative.</span>" } else if (time > 12 && time <= 17) { timeEl.innerHTML = "<span>☀️</span> <span>Good</span> <span>Afternoon,</span> <span>Creative.</span>" } else { timeEl.innerHTML = "<span>🌙</span> <span>Good</span> <span>Evening,</span> <span>Creative.</span>" } // 视口观察逻辑 const observer = new IntersectionObserver((entries) => { entries.forEach(entry => { if (entry.isIntersecting) { // 元素进入视口,添加类触发动画 entry.target.classList.add('in-view'); // 动画触发后取消观察,避免重复执行 observer.unobserve(entry.target); } }) }, { // 触发阈值:元素10%面积进入视口时启动动画,可按需调整0-1之间的数值 threshold: 0.1 }) observer.observe(timeEl);
补充说明
- 如果需要兼容IE这类极老旧浏览器,可以降级为监听
scroll事件,每次滚动时调用元素的getBoundingClientRect()方法计算和视口的位置关系,判断进入视口后再加类触发动画即可,但这种方案会在滚动时高频触发计算,性能远差于Intersection Observer,非必要不使用。 - 动画触发的阈值可以根据设计需求调整,
threshold: 0代表元素刚进入视口边缘就触发,threshold: 1代表元素完全进入视口后才触发。
内容的提问来源于stack exchange,提问作者JonnyFast
相关产品推荐
相关产品推荐

