如何用Framer Motion实现卡片背景色从左到右的Hover渐变效果?
实现卡片背景从左到右的悬停过渡效果(Framer Motion + React)
我需要复现一个卡片悬停效果:鼠标悬停时,卡片背景从var(--dark-bg)向左到右过渡变为网站主色var(--secondary)。目前用Framer Motion只能实现背景色整体同步变化,无法达成方向过渡效果,现有代码如下:
import { FC } from "react"; import { motion } from "framer-motion"; import { Stack, Typography, Divider, Button } from "@mui/material"; const NewsCard: FC = () => { return ( <motion.div whileHover={{ // backgroundColor: ["var(--dark-bg)", "var(--secondary)"] // background: "linear-gradient(to right, var(--dark-bg) 0%, var(--secondary) 100%)", // backgroundColor: "var(--secondary)", // backgroundSize: "250%" }} transition={{ duration: 0.3, ease: "easeIn" }} style={{ // height: "90%", // height: "100%", // border: "1px solid var(--secondary)", backgroundColor: "var(--dark-bg)" // background: "linear-gradient(to right, var(--dark-bg) 0%, var(--secondary) 100%)" }} > <Stack direction="row" justifyContent="space-between" alignItems="center" > <Stack direction="row" alignItems="center"> <Typography variant="overline"> Tag1 </Typography> <Typography variant="overline"> Tag2 </Typography> <Typography variant="overline"> Tag3 </Typography> </Stack> <Typography variant="overline"> {/* <time dateTime={ article.created_at!.toString() }> { dayjs(article.created_at).format("DD MMM YYYY") } </time> */} 11/02/2024 </Typography> </Stack> <Divider sx={{ borderColor: "secondary.main" }} /> <Stack justifyContent="space-between" style={{ // height: "93%" // display: "grid", // gridTemplateRows: "auto 1fr" }} > <Stack> <Typography variant="h4"> Ut sapiente ut nemo dicta et rem rerum ratione beatae. Ut sapiente ut nemo dicta et rem rerum ratione beatae. </Typography> <Stack spacing={1} direction="row"> <div style={{ width: "20px", height: "20px", backgroundColor: "red" }} /> <Typography>by</Typography> <Typography>Hazem Saeed</Typography> </Stack> </Stack> <Stack sx={{ mt: "7vh !important" }}> <Typography sx={{ width: "95%", height: "10vh", textOverflow: "ellipsis", // whiteSpace: "nowrap", overflow: "hidden" }} > Ipsam quam et non ut. Reprehenderit unde sunt minus. Sit quia similique sunt quam. Velit neque voluptatem quod. Et qui quam sint cupiditate sunt repellendus unde est temporibus. </Typography> <Stack alignItems="flex-end"> <Button variant="outlined" size="small" sx={{ width: "130px" }} > read more </Button> </Stack> </Stack> </Stack> </motion.div> ); }; export default NewsCard;
解决方案
要实现这种方向式的背景过渡,不能直接修改backgroundColor,而是需要通过叠加背景层+位移动画来实现。具体步骤:
- 给卡片容器设置
position: relative和overflow: hidden,限制背景层的显示范围 - 添加一个绝对定位的
motion.div作为过渡背景层,初始时完全偏移到卡片左侧(x: -100%) - 利用Framer Motion的
whileHover触发背景层的位移动画,使其从左到右覆盖整个卡片 - 确保卡片内容的层级高于过渡背景层,避免被遮挡
修改后的完整代码:
import { FC } from "react"; import { motion } from "framer-motion"; import { Stack, Typography, Divider, Button } from "@mui/material"; const NewsCard: FC = () => { return ( <div style={{ position: "relative", overflow: "hidden", backgroundColor: "var(--dark-bg)" }} > {/* 背景过渡层 */} <motion.div initial={{ x: "-100%" }} whileHover={{ x: 0 }} transition={{ duration: 0.3, ease: "easeIn" }} style={{ position: "absolute", top: 0, left: 0, width: "100%", height: "100%", backgroundColor: "var(--secondary)", zIndex: 0 }} /> {/* 卡片内容容器,设置z-index高于背景层 */} <Stack style={{ position: "relative", zIndex: 1, padding: "1rem" }} > <Stack direction="row" justifyContent="space-between" alignItems="center" > <Stack direction="row" alignItems="center" spacing={2}> <Typography variant="overline"> Tag1 </Typography> <Typography variant="overline"> Tag2 </Typography> <Typography variant="overline"> Tag3 </Typography> </Stack> <Typography variant="overline"> 11/02/2024 </Typography> </Stack> <Divider sx={{ borderColor: "secondary.main", my: 1 }} /> <Stack justifyContent="space-between"> <Stack spacing={2}> <Typography variant="h4"> Ut sapiente ut nemo dicta et rem rerum ratione beatae. Ut sapiente ut nemo dicta et rem rerum ratione beatae. </Typography> <Stack spacing={1} direction="row" alignItems="center"> <div style={{ width: "20px", height: "20px", backgroundColor: "red" }} /> <Typography>by</Typography> <Typography>Hazem Saeed</Typography> </Stack> </Stack> <Stack sx={{ mt: "7vh" }} spacing={2}> <Typography sx={{ width: "95%", height: "10vh", textOverflow: "ellipsis", overflow: "hidden" }} > Ipsam quam et non ut. Reprehenderit unde sunt minus. Sit quia similique sunt quam. Velit neque voluptatem quod. Et qui quam sint cupiditate sunt repellendus unde est temporibus. </Typography> <Stack alignItems="flex-end"> <Button variant="outlined" size="small" sx={{ width: "130px" }} > read more </Button> </Stack> </Stack> </Stack> </Stack> </div> ); }; export default NewsCard;
关键修改说明
- 将原
motion.div拆分为容器+背景过渡层+内容层结构,避免内容被背景层遮挡 - 背景过渡层使用
absolute定位,通过x属性的位移动画实现从左到右的填充效果 - 内容层设置
position: relative和z-index: 1,确保文字、按钮等内容始终可见 - 调整了部分Stack的
spacing和内边距,优化布局合理性
内容的提问来源于stack exchange,提问作者user10033434
相关产品推荐
相关产品推荐

