滚动时逐个元素渐隐的文本效果可以通过CSS过渡配合JavaScript滚动监听实现,核心思路是根据元素在视口中的位置动态调整其透明度,实现逐个消失的视觉感受。

实现原理
整个效果的实现分为两个核心部分,分别是样式定义和逻辑控制:
- 样式层:为文本元素设置默认的过渡属性,让透明度的变化更平滑,同时定义渐隐后的最终样式状态。
- 逻辑层:监听页面滚动事件,判断每个文本元素相对于视口的位置,当元素滚动到指定区域时,触发其透明度变化,并且通过延迟控制实现逐个渐隐的顺序。
基础样式准备
首先我们需要为文本容器和单个文本元素定义基础样式,这里给每个文本元素添加过渡效果,让透明度变化有平滑的动画:
/* 文本容器样式 */
.text-container {
padding: 20px;
max-width: 800px;
margin: 0 auto;
}
/* 单个文本元素样式 */
.text-item {
font-size: 18px;
line-height: 1.8;
margin-bottom: 20px;
/* 设置透明度过渡,时长0.5秒,缓动函数为 ease */
transition: opacity 0.5s ease;
/* 默认透明度为1,完全显示 */
opacity: 1;
}
/* 渐隐后的样式类 */
.text-item.fade-out {
/* 透明度变为0,完全隐藏 */
opacity: 0;
}
使用滚动事件监听实现
传统的实现方式是监听window的scroll事件,计算每个文本元素的位置,判断是否触发渐隐效果。为了避免滚动事件触发过于频繁,我们可以加入节流处理提升性能:
// 获取所有文本元素
const textItems = document.querySelectorAll('.text-item');
// 定义渐隐的触发阈值,元素底部距离视口顶部小于这个值时触发渐隐
const fadeThreshold = 200;
// 定义逐个渐隐的延迟时间,单位毫秒
const delayPerItem = 100;
// 节流函数,限制滚动事件的执行频率
function throttle(fn, delay) {
let timer = null;
return function() {
if (!timer) {
timer = setTimeout(() => {
fn.apply(this, arguments);
timer = null;
}, delay);
}
};
}
// 处理滚动逻辑的函数
function handleScroll() {
// 获取当前视口的高度
const windowHeight = window.innerHeight;
// 遍历所有文本元素
textItems.forEach((item, index) => {
// 获取元素的位置信息
const rect = item.getBoundingClientRect();
// 判断元素是否进入渐隐区域:元素底部距离视口顶部小于阈值,且元素还没有添加渐隐类
if (rect.bottom < fadeThreshold && !item.classList.contains('fade-out')) {
// 根据索引设置延迟,实现逐个渐隐
setTimeout(() => {
item.classList.add('fade-out');
}, index * delayPerItem);
}
});
}
// 监听滚动事件,使用节流处理
window.addEventListener('scroll', throttle(handleScroll, 100));
// 页面加载完成后先执行一次,处理初始状态
window.addEventListener('load', handleScroll);
使用Intersection Observer API实现
原生的滚动事件监听需要手动计算元素位置,性能开销相对较大,更推荐的方式是使用Intersection Observer API,它可以异步监听元素与视口的交叉状态,不需要频繁计算位置:
// 获取所有文本元素
const textItems = document.querySelectorAll('.text-item');
// 定义逐个渐隐的延迟时间,单位毫秒
const delayPerItem = 100;
// 创建观察器实例
const observer = new IntersectionObserver((entries) => {
entries.forEach((entry, index) => {
// 当元素离开视口时触发渐隐
if (!entry.isIntersecting) {
const item = entry.target;
// 获取元素在集合中的索引,用于计算延迟
const itemIndex = Array.from(textItems).indexOf(item);
// 避免重复添加渐隐类
if (!item.classList.contains('fade-out')) {
setTimeout(() => {
item.classList.add('fade-out');
}, itemIndex * delayPerItem);
}
}
});
}, {
// 视口的交叉阈值,0表示元素刚离开视口就触发
threshold: 0
});
// 遍历所有文本元素,开始观察
textItems.forEach(item => {
observer.observe(item);
});
效果优化建议
为了让效果更自然,你可以根据实际需求做以下调整:
- 调整
transition的时长和缓动函数,比如使用ease-in-out让渐隐的开始和结束更平缓。 - 修改渐隐的触发条件,比如可以设置元素进入视口一定比例后再触发渐隐,只需要调整
Intersection Observer的threshold参数即可。 - 如果需要渐隐后元素不占据布局空间,可以在
fade-out类中添加visibility: hidden或者display: none,但注意display属性不支持过渡动画。
注意事项
使用滚动事件监听时,一定要加入节流处理,否则滚动时频繁执行位置计算会严重影响页面性能。如果项目兼容要求允许,优先选择Intersection Observer API,它的性能表现更好,也不需要手动处理节流逻辑。
如果需要在渐隐后重新显示元素,只需要移除元素的fade-out类即可,你可以结合滚动方向判断,实现元素进入视口时渐显、离开时渐隐的双向效果。
CSS动画JavaScript滚动监听元素渐隐Intersection_Observer修改时间:2026-07-03 19:42:30