如何用HTML/CSS/JS实现环形旋转图片的定点放大与内容切换
解决方案
核心思路
- 保留父容器的旋转停顿动画,通过定时检测父容器的旋转角度,给处于右侧(90度位置)的圆形添加放大样式。
- 为每个圆形绑定对应的内容区块,默认隐藏,当对应圆形激活时自动切换显示内容。
完整代码实现
HTML 代码
<div id="parent-circle"> <div class="circle blue" data-content="content-blue">健康档案</div> <div class="circle pink" data-content="content-pink">运动记录</div> <div class="circle lime" data-content="content-lime">饮食日志</div> <div class="circle orange" data-content="content-orange">睡眠数据</div> </div> <!-- 对应每个圆形的内容区块 --> <div class="mt-5 content-container pt-2"> <div id="content-blue" class="content active"> <h1>健康档案</h1> <p class="w-75">Lorem ipsum dolor sit, amet consectetur adipisicing elit. Dolorum, doloremque!</p> </div> <div id="content-pink" class="content"> <h1>运动记录</h1> <p class="w-75">记录每日运动时长、步数及消耗卡路里,助你保持活力。</p> </div> <div id="content-lime" class="content"> <h1>饮食日志</h1> <p class="w-75">追踪每日摄入营养,合理搭配饮食,养成健康饮食习惯。</p> </div> <div id="content-orange" class="content"> <h1>睡眠数据</h1> <p class="w-75">分析睡眠周期,改善睡眠质量,让你拥有充沛精力。</p> </div> </div>
CSS 代码
body { width: 90vw; height: 90vh; display: flex; flex-direction: column; justify-content: center; align-items: center; margin: 0; } #parent-circle { position: relative; width: 20vw; height: 20vw; border: 0.4vw solid rgba(0, 0, 0, 0.4); border-radius: 50%; animation: rotate 14s infinite linear; } #parent-circle .circle { display: flex; justify-content: center; align-items: center; position: absolute; width: 30%; height: 30%; margin: -15%; border-radius: 50%; top: 50%; left: 50%; color: white; font-size: 0.8vw; transition: transform 0.3s ease; /* 反向旋转保持文字正向 */ animation: spin-reverse 14s infinite linear; } /* 放大激活状态 */ #parent-circle .circle.active { transform: scale(1.8); z-index: 10; } #parent-circle .circle.blue { background-color: #416ba9; transform: translate(10vw); } #parent-circle .circle.pink { background-color: #e6427a; transform: rotate(90deg) translate(10vw) rotate(-90deg); } #parent-circle .circle.lime { background-color: #cddb00; transform: rotate(180deg) translate(10vw) rotate(-180deg); } #parent-circle .circle.orange { background-color: #e0592a; transform: rotate(270deg) translate(10vw) rotate(-270deg); } .content-container { margin-top: 2rem; width: 60vw; } .content { display: none; } .content.active { display: block; } /* 父容器旋转动画 */ @keyframes rotate { 0%, 12.5% { transform: rotate(0deg); } 12.5%, 25% { transform: rotate(90deg); } 25%, 37.5% { transform: rotate(90deg); } 37.5%, 50% { transform: rotate(180deg); } 50%, 62.5% { transform: rotate(180deg); } 62.5%, 75% { transform: rotate(270deg); } 75%, 87.5% { transform: rotate(270deg); } 87.5%, 100% { transform: rotate(360deg); } } /* 子元素反向旋转,保持文字正向 */ @keyframes spin-reverse { from { transform: inherit rotate(0deg); } to { transform: inherit rotate(-360deg); } }
JavaScript 代码
const parentCircle = document.getElementById('parent-circle'); const circles = document.querySelectorAll('.circle'); const contents = document.querySelectorAll('.content'); const animationDuration = 14000; // 动画总时长14秒 const intervalTime = animationDuration / 8; // 每个阶段的时长:14s/8=1.75s // 定义每个旋转角度对应的激活圆形 const angleToCircleMap = { 0: '.blue', 90: '.pink', 180: '.lime', 270: '.orange', 360: '.blue' }; function updateActiveCircle() { // 获取当前动画进度,解析旋转角度 const computedStyle = window.getComputedStyle(parentCircle); const transform = computedStyle.getPropertyValue('transform'); let angle = 0; if (transform !== 'none') { const matrix = transform.split('(')[1].split(')')[0].split(','); const cos = parseFloat(matrix[0]); angle = Math.round(Math.acos(cos) * (180 / Math.PI)); const sin = parseFloat(matrix[1]); if (sin < 0) angle = 360 - angle; } // 匹配当前角度对应的圆形 let targetCircleSelector = ''; if (angle >= 0 && angle < 45) targetCircleSelector = angleToCircleMap[0]; else if (angle >= 45 && angle < 135) targetCircleSelector = angleToCircleMap[90]; else if (angle >= 135 && angle < 225) targetCircleSelector = angleToCircleMap[180]; else if (angle >= 225 && angle < 315) targetCircleSelector = angleToCircleMap[270]; else targetCircleSelector = angleToCircleMap[360]; // 移除所有激活状态 circles.forEach(circle => circle.classList.remove('active')); contents.forEach(content => content.classList.remove('active')); // 添加当前激活状态 const activeCircle = document.querySelector(targetCircleSelector); activeCircle.classList.add('active'); const contentId = activeCircle.dataset.content; document.getElementById(contentId).classList.add('active'); } // 定时检查更新,间隔略小于阶段时长避免延迟 setInterval(updateActiveCircle, intervalTime - 50); // 初始执行一次,确保页面加载时状态正确 updateActiveCircle();
代码说明
- HTML部分:给每个圆形添加
data-content属性绑定对应内容区块ID,新增四个内容区块通过active类控制显示/隐藏。 - CSS部分:新增
.active类实现圆形放大效果,调整子元素反向旋转动画时长与父容器同步,确保文字始终正向显示。 - JavaScript部分:定时检测父容器旋转角度,匹配当前处于右侧的圆形并添加激活状态,同时切换对应内容区块的显示。
内容的提问来源于stack exchange,提问作者Bollampalli Vinaykumar1119
相关产品推荐
相关产品推荐

