如何实现围绕用户头像下半部分的环形导航菜单及逐项加载动画?
实现头像下半部环形导航及加载动画
问题说明
需用<ul>和<li>构建围绕用户头像下半部分的环形导航栏,当前导航项全部显示在头像左侧;同时要实现页面加载时导航项逐个出现的动画效果。
解决方案
1. 环形布局实现(下半部分)
核心逻辑是将.navMenu设为相对定位容器,通过CSS transform: rotate() + translate() 计算每个导航项的位置,让它们分布在头像下半部分的圆弧上:
- 把
.navMenu设为相对定位,固定宽高并居中,作为导航项和头像的定位基准 - 头像居中放置在
.navMenu内部 - 针对5个导航项,计算出不同的旋转角度,让它们均匀分布在头像下半区域的圆弧上
2. 逐个加载动画实现
通过CSS关键帧动画定义显示过渡效果,给每个导航项设置递增的动画延迟,实现依次出现的顺序动画。
修改后的代码
JSX 文件
const Profile = () => { const { currentUser } = useContext(AuthContext); // 导航项数据,便于后续扩展 const navItems = [ { icon: <EmailIcon />, text: "Email" }, { icon: <EmailIcon />, text: "Email" }, { icon: <EmailIcon />, text: "Email" }, { icon: <EmailIcon />, text: "Email" }, { icon: <EmailIcon />, text: "Email" }, ]; return ( <div className="profile"> <ul className="navMenu"> <div className="avatarContainer"> <img src="https://w7.pngwing.com/pngs/81/570/png-transparent-profile-logo-computer-icons-user-user-blue-heroes-logo-thumbnail.png" alt="用户头像" className="avatarPic" /> </div> {navItems.map((item, index) => ( <li key={index} className="navItem"> {item.icon} <span className="navText">{item.text}</span> </li> ))} </ul> </div> ); }; export default Profile;
SCSS 文件
.profile { @include themify($themes) { background-color: themed("bgSoft"); height: 100vh; display: flex; justify-content: center; align-items: center; .navMenu { list-style-type: none; position: relative; width: 400px; height: 400px; padding: 0; margin: 0; } .avatarContainer { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); width: 200px; height: 200px; .avatarPic { width: 100%; height: 100%; border-radius: 50%; object-fit: cover; } } .navItem { position: absolute; top: 50%; left: 50%; width: 95px; height: 95px; border: solid 2px black; border-radius: 50%; display: flex; justify-content: center; align-items: center; cursor: pointer; transition: transform 0.3s ease; // 初始状态:透明+缩放0,用于动画 opacity: 0; transform: translate(-50%, -50%) scale(0); animation: fadeInScale 0.5s ease forwards; .navIcon { font-size: 3.5rem; } .navText { position: absolute; bottom: -20px; font-size: 1rem; opacity: 0; transition: opacity 0.3s ease; } &:hover { transform: translate(-50%, -50%) scale(1.1); .navText { opacity: 1; } } // 逐个设置位置和动画延迟 &:nth-child(2) { transform: translate(-50%, -50%) rotate(45deg) translateX(150px) rotate(-45deg); animation-delay: 0.1s; } &:nth-child(3) { transform: translate(-50%, -50%) rotate(90deg) translateX(150px) rotate(-90deg); animation-delay: 0.2s; } &:nth-child(4) { transform: translate(-50%, -50%) rotate(135deg) translateX(150px) rotate(-135deg); animation-delay: 0.3s; } &:nth-child(5) { transform: translate(-50%, -50%) rotate(-135deg) translateX(150px) rotate(135deg); animation-delay: 0.4s; } &:nth-child(6) { transform: translate(-50%, -50%) rotate(-45deg) translateX(150px) rotate(45deg); animation-delay: 0.5s; } } } } // 加载动画关键帧 @keyframes fadeInScale { to { opacity: 1; transform: translate(-50%, -50%) rotate(var(--rotate)) translateX(150px) rotate(calc(-1 * var(--rotate))); } }
代码说明
环形布局:
.navMenu作为相对定位容器,宽高设为400px(足够容纳头像和导航项)- 头像通过
transform: translate(-50%, -50%)居中在容器内 - 每个
.navItem先旋转方向,再平移到圆弧位置,最后反向旋转保持图标正向,5个项分别对应不同角度,均匀分布在头像下半区域
加载动画:
- 定义
fadeInScale关键帧,实现从透明、缩放0到完全显示的过渡 - 给每个
.navItem设置递增的animation-delay,实现逐个出现的顺序效果 - 保留原有hover时的缩放和文本显示逻辑
- 定义
内容的提问来源于stack exchange,提问作者Pisa Ponente
相关产品推荐
相关产品推荐

