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

使用Framer Motion实现卡片揭示动画时退出抖动问题求助

解决Framer Motion卡片揭示动画退出抖动问题

你的问题核心在于同时使用top/right这类触发重排的属性和scale动画,以及过渡配置不统一导致退出时的抖动。下面是修复后的代码和关键优化点:

关键优化项

  • 用transform: translate()替代top/right:translate属于GPU加速属性,不会触发页面重排,从根本上解决抖动问题
  • 统一过渡配置:确保进入、悬停、退出动画使用一致的缓动曲线和时长,避免状态切换时的突兀感
  • 明确exit状态配置:原来的代码未定义退出状态,导致Framer Motion无法正确处理退出过渡

修复后的完整代码

const PortfolioSection: FC = () => {
    const list = [
        {
            title: "abc",
            url: "https://www.example.com",
            image: "https://images.unsplash.com/photo-1488972685288-c3fd157d7c7a?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=1740&q=80"
        },
        {
            title: "klm",
            url: "https://www.example.com",
            image: "https://images.unsplash.com/photo-1487958449943-2429e8be8625?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=1740&q=80"
        },
        {
            title: "ost",
            url: "https://www.example.com",
            image: "https://images.unsplash.com/photo-1449157291145-7efd050a4d0e?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=1740&q=80"
        },
        {
            title: "xyz",
            url: "https://www.example.com",
            image: "https://images.unsplash.com/photo-1598818384697-62330d600309?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=687&q=80"
        }
    ];

    // 用translate替代top/right,统一过渡配置
    const imgMotion = {
        initial: {
            // 初始状态:无偏移,原尺寸
            translateX: 0,
            translateY: 0,
            scale: 1
        },
        hover: {
            // 悬停时:向右下偏移25%,缩小到0.5倍
            translateX: "25%",
            translateY: "25%",
            scale: 0.5,
            transition: {
                duration: 0.3,
                type: "tween",
                ease: "easeInOut"
            }
        },
        exit: {
            // 退出状态和初始状态一致,过渡和悬停保持统一
            translateX: 0,
            translateY: 0,
            scale: 1,
            transition: {
                duration: 0.3,
                type: "tween",
                ease: "easeInOut"
            }
        }
    };

    return (
        <HomePageSection>
            <Grid
                container
                rowSpacing={4}
                columnSpacing={2}
                justifyContent="center"
                sx={{ height: "100%" }}
            >
                {list.map((item, i) => (
                    <Grid
                        key={i}
                        size={{ md: 6, xs: 12 }}
                    >
                        <motion.div
                            initial="initial"
                            whileHover="hover"
                            whileTap="hover"
                            exit="exit"
                            style={{
                                width: "100%",
                                height: "30vh",
                                position: "relative",
                                border: "4px solid green",
                                overflow: "hidden" // 加上overflow:hidden,避免图片超出容器
                            }}
                        >
                            <div
                                style={{
                                    height: "50%",
                                    display: "grid",
                                    placeContent: "center",
                                    textTransform: "uppercase",
                                    backgroundColor: "black",
                                    color: "white"
                                }}
                            >
                                <Typography variant="h4">
                                    {item.title}
                                </Typography>
                            </div>
                            <motion.div
                                variants={imgMotion}
                                style={{
                                    height: "100%",
                                    width: "100%",
                                    backgroundImage: `url(${item.image})`,
                                    backgroundSize: "cover",
                                    backgroundPosition: "center center",
                                    zIndex: 10,
                                    position: "absolute",
                                    top: 0,
                                    right: 0 // 固定初始位置,用transform控制偏移
                                }}
                            />
                            <Link
                                href={item.url}
                                target="_blank"
                                style={{
                                    position: "absolute",
                                    bottom: 0,
                                    right: 0,
                                    height: "50%",
                                    width: "50%",
                                    display: "grid",
                                    placeContent: "center",
                                    backgroundColor: "black",
                                    zIndex: 20 // 确保链接在图片上方
                                }}
                            >
                                Read more
                            </Link>
                        </motion.div>
                    </Grid>
                ))}
            </Grid>
        </HomePageSection>
    );
};

额外注意点

  • 给父容器加上overflow: hidden,避免图片动画时超出容器范围
  • 给链接设置更高的z-index,确保悬停时依然可以点击
  • 如果使用纯CSS方案,同样要替换top/right为transform: translate(),并确保过渡属性只包含transform,减少性能开销

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.17 12:45:54