为何JavaScript中CSS骰子动画不生效?求CSS优化方案
骰子动画不生效问题解决与CSS优化方案
我在用户点击按钮执行骰子逻辑时,想给Cube添加动画效果,代码逻辑正常但动画无法生效,就算用了timeout也没用。相关代码如下:
原代码展示
HTML
<div class="cube"> <div class="side top"></div> <div class="side bottom"></div> <div class="side front"></div> <div class="side back"></div> <div class="side right"></div> <div class="side left"></div> </div> <input type="submit" value="Roll" id="roll">
CSS
.cube { position: relative; width: 100px; height: 100px; transform-style: preserve-3d; transform: rotateX(193deg) rotateY(269deg); animation: rolling 4s; } .anim { animation: rolling 3s; } @keyframes rolling { 50% { transform: rotateX(455deg) rotateY(455deg); } }
JS
document.getElementById("roll").addEventListener("click", function () { side = Math.floor(Math.random() * 6); console.log(`dic Case : ${side}`); document.getElementsByClassName("cube")[0].classList.add("anim"); setTimeout(() => { roll(side); }, 4000); })
动画不生效的原因及修复
- CSS优先级冲突:
.cube类本身已设置animation属性,.anim类优先级与它相同,浏览器会优先使用先定义的样式,导致新增动画不生效。 - 动画未重置:首次添加
.anim类执行完动画后,再次点击按钮时,浏览器认为元素已处于该动画状态,不会重新触发。
修复代码
修改后的CSS
.cube { position: relative; width: 100px; height: 100px; transform-style: preserve-3d; transform: rotateX(193deg) rotateY(269deg); /* 移除初始动画,仅在点击时触发 */ } /* 提升优先级,确保动画样式生效 */ .cube.anim { animation: rolling 3s forwards; /* forwards保持动画结束状态 */ } @keyframes rolling { 0% { transform: rotateX(193deg) rotateY(269deg); /* 明确起始状态 */ } 50% { transform: rotateX(455deg) rotateY(455deg); } 100% { transform: rotateX(193deg) rotateY(269deg); /* 回到初始状态,可根据roll逻辑调整 */ } }
修改后的JS
document.getElementById("roll").addEventListener("click", function () { const cube = document.getElementsByClassName("cube")[0]; // 先移除动画类,强制浏览器重绘后再添加,触发动画重置 cube.classList.remove("anim"); void cube.offsetWidth; cube.classList.add("anim"); side = Math.floor(Math.random() * 6); console.log(`dic Case : ${side}`); setTimeout(() => { roll(side); }, 3000); // 与动画时长3s保持一致,确保逻辑和动画同步 })
CSS代码优化方案
1. 变量统一管理
用CSS变量存储可复用参数,方便后续维护和修改:
:root { --cube-size: 100px; --init-rotate-x: 193deg; --init-rotate-y: 269deg; --roll-duration: 3s; --cube-border: 2px solid #333; }
2. 完善3D骰子面布局
原代码缺少骰子面的3D定位,添加以下样式让骰子呈现真正的3D效果:
.side { position: absolute; width: var(--cube-size); height: var(--cube-size); background: #fff; border: var(--cube-border); box-sizing: border-box; display: flex; align-items: center; justify-content: center; font-size: 2rem; } .top { transform: rotateX(90deg) translateZ(calc(var(--cube-size)/2)); } .bottom { transform: rotateX(-90deg) translateZ(calc(var(--cube-size)/2)); } .front { transform: translateZ(calc(var(--cube-size)/2)); } .back { transform: rotateY(180deg) translateZ(calc(var(--cube-size)/2)); } .right { transform: rotateY(90deg) translateZ(calc(var(--cube-size)/2)); } .left { transform: rotateY(-90deg) translateZ(calc(var(--cube-size)/2)); }
3. 动画效果优化
添加缓动函数让滚动更自然,同时扩展动画关键帧让滚动过程更流畅:
.cube.anim { animation: rolling var(--roll-duration) cubic-bezier(0.36, 0.07, 0.19, 0.97) forwards; } @keyframes rolling { 0% { transform: rotateX(var(--init-rotate-x)) rotateY(var(--init-rotate-y)); } 25% { transform: rotateX(calc(var(--init-rotate-x) + 180deg)) rotateY(calc(var(--init-rotate-y) + 90deg)); } 50% { transform: rotateX(calc(var(--init-rotate-x) + 360deg)) rotateY(calc(var(--init-rotate-y) + 180deg)); } 75% { transform: rotateX(calc(var(--init-rotate-x) + 540deg)) rotateY(calc(var(--init-rotate-y) + 270deg)); } 100% { transform: rotateX(calc(var(--init-rotate-x) + 720deg)) rotateY(calc(var(--init-rotate-y) + 360deg)); } }
4. 响应式适配
改用视窗单位替代固定像素,让骰子适配不同屏幕尺寸:
:root { --cube-size: 10vmin; /* 基于视窗大小自适应 */ }
内容的提问来源于stack exchange,提问作者Parmar Aayush
相关产品推荐
相关产品推荐

