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

实现鼠标悬浮时溢出文本滚动至末尾,离开时平滑复位动画

实现文本容器悬浮滚动与平滑复位效果

要解决鼠标离开时文本直接跳回的问题,我们可以用CSS过渡替代单向动画,让悬浮和离开状态的切换都保持平滑,同时优化溢出判断逻辑以适配窗口大小变化。

修改后的React组件代码

import { useEffect, useRef, useState } from 'react';
import classes from './test.module.css';

const Test = () => {
    const textRef = useRef(null);
    const containerRef = useRef(null);

    const [isHovered, setIsHovered] = useState(false);
    const [isOverflowing, setIsOverflowing] = useState(false);

    // 检查文本是否溢出容器
    const checkOverflow = () => {
        if (!textRef.current || !containerRef.current) return;
        const textWidth = textRef.current.offsetWidth;
        const containerWidth = containerRef.current.offsetWidth;
        setIsOverflowing(textWidth > containerWidth);
    };

    useEffect(() => {
        checkOverflow();
        // 监听窗口大小变化,实时更新溢出状态
        window.addEventListener('resize', checkOverflow);
        return () => window.removeEventListener('resize', checkOverflow);
    }, []);

    return (
        <div>
            <div 
                ref={containerRef} 
                className={classes.animated} 
                onMouseEnter={() => setIsHovered(true)}
                onMouseLeave={() => setIsHovered(false)}
            >
                <h3 
                    className={classes.text} 
                    ref={textRef}
                    style={{
                        // 根据悬浮状态和溢出状态计算位移
                        transform: isHovered && isOverflowing 
                            ? `translateX(calc(${containerRef.current?.offsetWidth}px - ${textRef.current?.offsetWidth}px))` 
                            : 'translateX(0)'
                    }}
                >
                    This is some very very very long text
                </h3>
            </div>
        </div>
    );
};

export default Test;

修改后的CSS代码

.animated {
    margin: 200px;
    position: relative;
    white-space: nowrap;
    max-width: 300px;
    width: 100%;
    overflow: hidden;
    background: #0c0c0c;
    display: inline-block;
    border: 1px solid white;
}

.text {
    color: #fff;
    display: inline-block;
    position: relative;
    /* 统一设置过渡动画,悬浮/离开时自动生效 */
    transition: transform 3s linear;
}

关键修改说明

  1. 用CSS过渡替代单向动画:通过transition属性控制transform的平滑变化,无需定义反向动画,悬浮和离开状态切换时自动触发平滑过渡。
  2. 精准计算滚动位移:使用calc(${containerWidth}px - ${textWidth}px)确保文本刚好滚动到容器末尾,不会出现过度滚动。
  3. 添加窗口resize监听:实时更新溢出状态,避免窗口大小变化后动画失效。

如果你偏好使用@keyframes实现,也可以定义正向和反向两个动画,通过切换类名触发:

可选方案(基于@keyframes)

CSS代码

.animated {
    margin: 200px;
    position: relative;
    white-space: nowrap;
    max-width: 300px;
    width: 100%;
    overflow: hidden;
    background: #0c0c0c;
    display: inline-block;
    border: 1px solid white;
}

.text {
    color: #fff;
    display: inline-block;
    position: relative;
}

.scroll-forward {
    animation: scrollForward 3s linear forwards;
}

.scroll-back {
    animation: scrollBack 3s linear forwards;
}

@keyframes scrollForward {
    0% { transform: translateX(0); }
    10% { transform: translateX(0); }
    90% { transform: translateX(calc(100% - var(--text-width))); }
    100% { transform: translateX(calc(100% - var(--text-width))); }
}

@keyframes scrollBack {
    0% { transform: translateX(calc(100% - var(--text-width))); }
    100% { transform: translateX(0); }
}

React组件中修改类名和样式

<h3 
    className={`${classes.text} ${
        isHovered && isOverflowing ? classes['scroll-forward'] : 
        isOverflowing ? classes['scroll-back'] : ''
    }`} 
    ref={textRef}
    style={{
        '--text-width': `${textRef.current?.offsetWidth}px`
    }}
>
    This is some very very very long text
</h3>

内容的提问来源于stack exchange,提问作者Cody

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.17 10:53:22