使用Framer Motion优化React导航栏动画的技术问询
解决方案:实现固定左侧+逐个从左到右入场的导航栏动画
你的核心问题在于:
- 导航容器宽度扩展时,链接容器跟着整体移动,导致视觉上呈现从右侧滑入的效果
- 所有链接同时显示,没有实现从左到右的序列入场动画
以下是具体改进方案:
关键修改点
- 固定链接容器位置:让链接始终锚定在左侧,不受导航容器宽度变化的影响
- 添加序列动画:给每个链接设置独立的位移动画,通过
staggerChildren实现逐个从左到右显示 - 优化容器动画逻辑:调整导航容器的过渡曲线,移除不必要的属性动画干扰
修改后的完整代码
import Link from "next/link"; import React, { useState } from "react"; import HamburgerIcon from "./icons/HamburgerIcon"; import { motion } from "framer-motion"; const MenuDesktop = () => { const [isHovered, setIsHovered] = useState(false); const navVariants = { initial: { width: "5rem", zIndex: 0 }, hover: { width: "100%", zIndex: 1 }, }; // 单个链接的动画变体:从左侧偏移位置入场 const linkItemVariants = { initial: { x: -20, opacity: 0 }, hover: { x: 0, opacity: 1, transition: { duration: 0.4 } } }; // 链接容器的变体:控制子元素的序列动画 const linkContainerVariants = { initial: { opacity: 0 }, hover: { opacity: 1, transition: { staggerChildren: 0.1, // 每个链接间隔0.1秒入场 delayChildren: 0.2 // 等待导航容器展开一点后再开始链接动画 } } }; const iconVariants = { initial: { opacity: 1 }, hover: { opacity: 0, transition: { duration: 0.3 } }, }; return ( <div className="flex p-0.5 h-20 rounded-15px bg-cc-invert justify-center items-stretch overflow-hidden"> <div className="relative"> <motion.nav className="flex relative h-full overflow-hidden" // 改为overflow-hidden,避免滚动条 initial="initial" animate={isHovered ? "hover" : "initial"} variants={navVariants} transition={{ width: { duration: 0.75, ease: "easeInOut" }, }} onHoverStart={() => setIsHovered(true)} onHoverEnd={() => setIsHovered(false)} > {/* 链接容器:设置flex-shrink:0固定位置,避免被挤压 */} <motion.div className="font-dmMono tracking-wider text-cc-dark-brown flex items-center gap-2 text-xs uppercase pl-4 bg-cc-invert flex-shrink-0" variants={linkContainerVariants} initial="initial" animate={isHovered ? "hover" : "initial"} > {/* 每个链接单独用motion包裹,应用单个动画变体 */} <motion.div variants={linkItemVariants}> <Link className="px-2 whitespace-nowrap" href="/development"> Development </Link> </motion.div> <motion.div variants={linkItemVariants}> <Link className="px-2 whitespace-nowrap" href="/energo"> Energo </Link> </motion.div> <motion.div variants={linkItemVariants}> <Link className="px-2 whitespace-nowrap" href="/company"> Company </Link> </motion.div> <motion.div variants={linkItemVariants}> <Link className="px-2 whitespace-nowrap" href="/news"> News </Link> </motion.div> <motion.div variants={linkItemVariants}> <Link className="px-2 whitespace-nowrap" href="/career"> Career </Link> </motion.div> </motion.div> </motion.nav> <motion.div className="absolute top-7 right-7 flex items-center cursor-pointer z-10" // 提高z-index确保在导航上层 initial="initial" animate={isHovered ? "hover" : "initial"} variants={iconVariants} > <HamburgerIcon className="h-5 cursor-pointer" /> </motion.div> </div> <Link href="/" className="font-dmMono tracking-wider text-cc-dark-brown flex items-center justify-center p-4 bg-cc-light-brown rounded-15px" > <span className="uppercase text-xs px-2">Contact</span> </Link> </div> ); }; export default MenuDesktop;
核心优化说明
- 固定链接位置:给链接容器添加
flex-shrink-0,确保它不会随着导航容器的宽度变化被挤压,始终锚定在左侧。 - 序列入场动画:
- 单个链接的
linkItemVariants设置初始向左偏移+透明,hover时回到原位并显示 - 链接容器通过
staggerChildren实现子元素逐个动画,delayChildren让导航容器先展开一部分再启动链接动画,视觉更自然
- 单个链接的
- 容器动画优化:移除导航容器的
opacity动画,避免和链接的透明度过渡冲突;将overflow-auto改为overflow-hidden,消除不必要的滚动条。 - 汉堡图标调整:提高图标
z-index,确保在导航展开过程中可正常交互,同时缩短动画时长让隐藏效果更流畅。
内容的提问来源于stack exchange,提问作者Filip Kuna
相关产品推荐
相关产品推荐

