如何将渐变背景动画与实时时间同步
实现日月动画与实时时间同步的方案
你已经完成了包含日月元素的天空背景动画效果,现在要让动画和实时时间绑定,让日月位置、天空背景真实反映当前时段,下面是具体实现方案:
实现思路
不再依赖CSS的循环动画,而是通过JavaScript计算当前时间在一天中的占比,将这个占比映射为日月轨道的旋转角度和各时段背景的透明度,同时定时更新状态保持同步。
具体步骤
1. 调整CSS样式
移除.sky__dawn、.sky__noon等元素上的infinite循环动画,同时去掉.orbit的循环动画(保留关键帧作为透明度计算的参考),改为通过JS动态控制元素的透明度和旋转角度。
2. 编写时间同步逻辑
- 获取当前时间,计算从0点到现在的总分钟数,除以一天的总分钟数(1440)得到时间占比
- 根据时间占比计算太阳轨道的旋转角度:对应日出(0点后)到日落(12点后)的位置,12点后隐藏太阳
- 计算月亮轨道的旋转角度:对应12点后出现到次日0点隐藏的位置,和太阳反向运动
- 模拟原CSS动画的透明度变化,根据时间占比设置各时段背景的透明度
3. 定时更新状态
设置每分钟更新一次状态,确保动画和时间始终同步。
修改后的完整代码
CSS
@keyframes sunrise { from { transform: rotate(-45deg); } to { transform: rotate(315deg); } } @keyframes moonrise { from { transform: rotate(0deg); } to { transform: rotate(180deg); } } @keyframes dawn { 0% { opacity: 0; } 10% { opacity: 1; } 60% { opacity: 0; } } @keyframes noon { 0% { opacity: 0; } 50% { opacity: 1; } 75% { opacity: 0; } } @keyframes dusk { 0% { opacity: 0; } 50% { opacity: 0; } 70% { opacity: 1; } 90% { opacity: 0; } } @keyframes midnight { 0% { opacity: 1; } 25% { opacity: 0; } 50% { opacity: 0; } 80% { opacity: 1; } } body { background-color: rgb(37, 29, 24); margin: 0; } .sky { width: 100vw; height: 100vh; position: relative; top: 0; left: 0; overflow: hidden; } .sky__phase { position: absolute; top: 0; left: 0; height: 100%; width: 100%; transition: opacity 0.5s ease; } .sky__dawn { background: linear-gradient(0deg, rgba(254, 215, 102, 1) 0%, rgba(205, 237, 246, 1) 100%); } .sky__noon { background: linear-gradient(0deg, rgba(205, 237, 246, 1) 0%, rgba(36, 123, 160, 1) 100%); } .sky__dusk { background: linear-gradient(0deg, rgba(255, 32, 110, 1) 0%, rgba(10, 0, 94, 1) 100%); } .sky__midnight { background: linear-gradient(0deg, rgba(2, 0, 20, 1) 0%, rgba(10, 0, 94, 1) 100%); } .orbit { position: relative; width: 500px; height: 500px; margin: 200px auto; transform-origin: center; } .moon-orbit { position: absolute; width: 100%; height: 100%; transform-origin: center; } @media (min-width: 768px) { .orbit { width: 100px; height: 700px; margin: 150px auto; } } @media screen and (min-width: 1080px) and (max-width: 1920px) { .orbit { width: 600px; height: 1100px; margin: 1000px auto; } } .sun { position: absolute; top: -40px; left: -40px; width: 80px; height: 80px; background-color: rgb(254, 215, 102); border-radius: 50%; box-shadow: 0 0 14px 14px rgba(254, 215, 102, 0.2); } .moon { position: absolute; bottom: -40px; right: -40px; width: 80px; height: 80px; border-radius: 50%; background-color: #fff; box-shadow: 0 0 7px 7px rgba(255, 255, 255, 0.2); }
HTML
<div class="sky"> <div class="sky__phase sky__dawn"></div> <div class="sky__phase sky__noon"></div> <div class="sky__phase sky__dusk"></div> <div class="sky__phase sky__midnight"></div> <div class="orbit"> <div class="sun"></div> <div class="moon-orbit"> <div class="moon"></div> </div> </div> </div>
JavaScript
function updateSky() { const now = new Date(); const totalMinutes = now.getHours() * 60 + now.getMinutes(); const dayPercentage = totalMinutes / 1440; // 一天共1440分钟 // 控制太阳旋转与显示:0-12小时显示,对应-45deg到315deg const sunRotation = dayPercentage <= 0.5 ? (-45 + dayPercentage * 360) : 315; document.querySelector('.orbit').style.transform = `rotate(${sunRotation}deg)`; document.querySelector('.sun').style.opacity = dayPercentage >= 0.5 ? 0 : 1; // 控制月亮旋转与显示:12-24小时显示,对应180deg到0deg const moonRotation = dayPercentage >= 0.5 ? (180 - (dayPercentage - 0.5) * 360) : 180; document.querySelector('.moon-orbit').style.transform = `rotate(${moonRotation}deg)`; document.querySelector('.moon').style.opacity = dayPercentage < 0.5 ? 0 : 1; // 设置各时段背景透明度 document.querySelector('.sky__dawn').style.opacity = getDawnOpacity(dayPercentage); document.querySelector('.sky__noon').style.opacity = getNoonOpacity(dayPercentage); document.querySelector('.sky__dusk').style.opacity = getDuskOpacity(dayPercentage); document.querySelector('.sky__midnight').style.opacity = getMidnightOpacity(dayPercentage); } // 模拟原dawn动画的透明度变化 function getDawnOpacity(percent) { const dayFraction = percent * 100; if (dayFraction <= 10) return dayFraction / 10; if (dayFraction <= 60) return 1 - (dayFraction - 10) / 50; return 0; } // 模拟原noon动画的透明度变化 function getNoonOpacity(percent) { const dayFraction = percent * 100; if (dayFraction <= 50) return dayFraction / 100; if (dayFraction <= 75) return 1 - (dayFraction - 50) / 25; return 0; } // 模拟原dusk动画的透明度变化 function getDuskOpacity(percent) { const dayFraction = percent * 100; if (dayFraction <= 50) return 0; if (dayFraction <= 70) return (dayFraction - 50) / 20; if (dayFraction <= 90) return 1 - (dayFraction - 70) / 20; return 0; } // 模拟原midnight动画的透明度变化 function getMidnightOpacity(percent) { const dayFraction = percent * 100; if (dayFraction <= 25) return 1 - dayFraction / 25; if (dayFraction <= 80) return 0; return (dayFraction - 80) / 20; } // 页面加载时初始化 updateSky(); // 每分钟更新一次,保持时间同步 setInterval(updateSky, 60000);
内容的提问来源于stack exchange,提问作者mindprojx
相关产品推荐
相关产品推荐

