You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React中如何在元素进入视口时正确触发单次CSS动画

解决方案

问题原因

  • 动画重复触发:当前useOnScreen钩子会在元素离开视口时把visible重置为false,再次进入时又会设为true,相当于重新给元素绑定动画属性,导致动画反复执行。
  • 初始状态跳动:你的h2元素没有设置初始top值,默认是0,动画触发时第一帧会跳转到@keyframes定义的top: 100%才开始执行动画,就出现了先消失再滑入的异常效果。同时缺少animation-fill-mode: forwards配置,动画结束后会回到初始样式。

修复后代码

JSX代码

import React, {useEffect, useRef, useState} from 'react'
import './landing.scss'

function useOnScreen(options){
    const ref = React.useRef(); 
    const [visible, setVisible] = React.useState(false);

    React.useEffect(() => {
        const observer = new IntersectionObserver(([entry]) => {
            // 仅当元素首次进入视口时更新状态,后续不再修改
            setVisible(prevState => prevState || entry.isIntersecting);
        }, options);

        if (ref.current) {
            observer.observe(ref.current);
        }

        return () => {
            if (ref.current) {
                observer.unobserve(ref.current);
            }
        }

    }, [ref, options])

    return [ref, visible];
}

const Landing = () => {
    const [ref, visible] = useOnScreen();

    return(
        <>
        {/* 给监听元素绑定ref,保证Intersection Observer正常工作 */}
        <div className="titleBox" ref={ref}>
            <h2 style={{ 
                animationDuration: `0.5s`, 
                animationIterationCount: 1, 
                animationName: visible ? "showTopText" : `none`, 
                animationDelay: "0.3s", 
                animationTimingFunction: "ease",
                // 动画结束后保留最后一帧样式
                animationFillMode: 'forwards'
            }}>My text</h2>
        </div>
        </>
    )
}

SCSS代码

@keyframes showTopText {
    0% {top: 100%;}
    100% {top: 0;}
}

.titleBox{
    width: 100%;
    height: 64px;
    overflow: hidden;
    position: relative;

    h2{
        font-size: 56px;
        line-height: 64px;
        width: 100%;
        font-weight: normal;
        position: absolute;
        // 设置初始top值和动画起始状态一致,避免跳动
        top: 100%;
    }
}

核心修改说明

  1. 修改useOnScreen的状态更新逻辑,visible一旦变为true就不再重置,保证动画只触发一次。
  2. 给目标元素绑定ref,保证Intersection Observer能正常监听元素的可见状态。
  3. SCSS中给h2添加初始top: 100%,和动画起始状态对齐,避免动画触发时的跳动。
  4. 新增animationFillMode: 'forwards'配置,动画结束后保持top: 0的最终状态,不会回到初始的top: 100%。

内容的提问来源于stack exchange,提问作者Hugo Barbé

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.06 05:30:03