React中如何实现滚动触发的元素垂直上移遮罩擦除动画?
问题描述
使用React.js开发时,需要复刻指定站点的文字垂直上移擦除动画:文字从遮挡区域后方向上移动显现,滚动到对应元素位置时触发。仅复用位移动画CSS代码时,无法实现擦除效果。
参考动画效果:
尝试使用的CSS代码片段:
transition-delay: .9s; transition: transform 1.3s cubic-bezier(.075, .82, .165, 1); transform: translateY(0%);
核心实现原理
之前的代码只实现了文字位移动画,缺失了遮罩裁切结构,这是擦除效果的核心:需要两层嵌套元素,外层容器设置overflow: hidden作为可视区域边界,文字初始位于外层容器可视范围下方,上移过程中超出外层容器的部分会被隐藏,自然形成从下往上擦除显现的效果。
分步实现方案
1. 基础DOM结构与CSS样式
先写两层嵌套的结构,搭配对应状态样式:
{/* 外层:遮罩裁切容器 */} <div className="text-mask"> {/* 内层:需要做动画的文字元素 */} <h1 className="sliding-text">A DIGITAL DESIGN STUDIO DRIVEN BY RESEARCH & STRATEGY</h1> </div>
对应CSS代码:
/* 遮罩容器:固定可视范围,超出部分直接隐藏 */ .text-mask { overflow: hidden; /* 行高和容器高度匹配,避免文字漏出 */ line-height: 1.1; } /* 文字初始状态:完全下移到遮罩容器外,默认不可见 */ .sliding-text { margin: 0; transform: translateY(100%); opacity: 0; /* 直接复用提取的缓动参数即可 */ transition: transform 1.3s cubic-bezier(.075, .82, .165, 1), opacity 1.3s cubic-bezier(.075, .82, .165, 1); transition-delay: .9s; } /* 动画激活状态:文字回到遮罩容器内的正常位置 */ .text-mask.in-view .sliding-text { transform: translateY(0); opacity: 1; }
2. 滚动触发逻辑
两种实现方式可选,不需要引入额外依赖也能实现:
- 原生轻量方案:用浏览器原生
IntersectionObserverAPI写一个自定义React Hook,监听元素是否进入视口,进入后给遮罩容器加上in-view类名触发动画即可,示例代码:
import { useEffect, useRef, useState } from 'react'; // 视口进入监听Hook function useScrollIn(triggerThreshold = 0.15) { const targetRef = useRef(null); const [isInView, setIsInView] = useState(false); useEffect(() => { const observer = new IntersectionObserver((entries) => { const [entry] = entries; if (entry.isIntersecting) { setIsInView(true); // 动画只触发一次,触发后取消监听 observer.unobserve(entry.target); } }, { threshold: triggerThreshold }); const currentTarget = targetRef.current; if (currentTarget) observer.observe(currentTarget); return () => { if (currentTarget) observer.unobserve(currentTarget); } }, [triggerThreshold]); return [targetRef, isInView]; } // 业务组件中使用 function HeroSection() { const [textMaskRef, isTextInView] = useScrollIn(); return ( <section> <div ref={textMaskRef} className={`text-mask ${isTextInView ? 'in-view' : ''}`} > <h1 className="sliding-text">A DIGITAL DESIGN STUDIO DRIVEN BY RESEARCH & STRATEGY</h1> </div> </section> ) }
- 依赖方案:如果项目中有大量滚动动画需求,可以引入
react-intersection-observer简化监听逻辑,需要做复杂序列动画时搭配framer-motion可以快速实现逐字延迟、多元素联动的效果,不用手动写CSS类名切换。
3. 效果优化点
- 如果要实现逐词/逐字擦除的效果,把文字拆分为独立的span标签,每个span外层单独套一层mask容器,给每个span的动画设置递增的
transition-delay即可。 - 遮罩容器不要加上下padding,避免初始状态下文字边缘漏出。
- 动画延迟、时长参数可以根据页面整体节奏调整,提取的缓动曲线参数和目标效果一致,不需要修改。
内容的提问来源于stack exchange,提问作者blue
相关产品推荐
相关产品推荐

