3D 硬币翻转组件(CSS 圆柱硬币抛掷动画,时长/连抛可调)

CSSJS 许可:自研原创

3D 硬币翻转组件:CSS preserve-3d 构建带侧面分段的正反面硬币,JS 随机抛掷 4-6 圈并判定正反面,翻转时长与自动连抛可调,自研实现零依赖零图片。

效果演示(真实可交互)

¥正面
反面

点击「抛硬币」开始

完整代码

硬币由三部分组成:正面圆面、背面圆面(rotateY(180deg) 翻转)、以及 20 个围绕圆周分布的小矩形拼成的圆柱侧面。抛掷时用一个带减速曲线的 CSS transition 把累计角度一次性推进 4-6 整圈加 0/180°,动画结束后按最终角度取模判定正反。

<div class="scene">
  <div class="coin" id="coin">
    <div class="face face--front"><b>¥</b><span>正面</span></div>
    <div class="face face--back"><b>★</b><span>反面</span></div>
    <div class="edge"><span style="--i:0"></span><span style="--i:1"></span></div>
  </div>
</div>
.scene { perspective: 900px; display: flex; align-items: center; justify-content: center; height: 340px; }
.coin {
  position: relative; width: 132px; height: 132px;
  transform-style: preserve-3d;
}
.face {
  position: absolute; inset: 0; border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  backface-visibility: hidden;
}
.face--front { background: radial-gradient(circle at 35% 30%, #ffe9a8, #f5b83d 55%, #c98a16); transform: translateZ(6px); }
.face--back  { background: radial-gradient(circle at 35% 30%, #e8eef8, #b9c4d6 55%, #8fa0b8); transform: rotateY(180deg) translateZ(6px); }
.edge { position: absolute; left: 50%; top: 50%; width: 0; height: 0; transform-style: preserve-3d; }
.edge span {
  position: absolute; left: -11px; top: -7px; width: 22px; height: 14px;
  background: linear-gradient(90deg, #e8c15a, #a87a1e);
  transform: rotateY(calc(var(--i) * 18deg)) translateZ(66px);   /* 20 段 × 18° */
}
let rot = 0;
function toss() {
  const spins = 4 + Math.floor(Math.random() * 3);   // 4-6 整圈
  const side = Math.round(Math.random());            // 0 正 / 1 反
  const target = rot + spins * 360 + (side ? 180 : 0);
  coin.style.transition = 'transform 1200ms cubic-bezier(.23,.7,.3,1)';
  coin.style.transform = 'rotateY(' + target + 'deg)';
  setTimeout(() => {
    const mod = ((target % 360) + 360) % 360;
    result.textContent = mod < 180 ? '🎉 正面' : '🎉 反面';
    rot = target;
  }, 1260);
}

参数说明

参数位置说明
翻转时长transition 的 1200ms演示中 600-2200ms 可调
抛掷圈数spins 随机 4-6圈数越多翻转越「猛」
结果判定target % 360 < 180最终角度决定正反面
硬币厚度.edge span 高度分段高度即硬币侧面厚度
自动连抛setInterval每 2.2s 自动抛一次

兼容性与性能

常见问题

Q: 硬币看起来是「纸片」而不是立体硬币? 侧面分段缺失或高度太小都会导致此现象。确认 .edge spantranslateZ 与硬币半径一致(132px 硬币为 66px),且分段数量 ≥ 12。

Q: 翻转后正反判定和视觉不一致? 判定公式 target % 360 在负角度时会出错,务必先加 360 取模(((x % 360) + 360) % 360)。此外请勿在 transition 未结束时连续抛掷,演示中已用 busy 标志互斥。

Q: 想让硬币朝上/朝下抛(绕 X 轴)怎么改?rotateY 全部换成 rotateX,同时把侧面分段的分布轴从 Y 改为 X(rotateX(i × 18deg) translateZ(66px)),即可得到纵向翻转的硬币。

Q: 可以商用吗? 可以。本组件为粤喵自研原创代码,免费商用无需署名,币面文字、颜色、抛掷节奏均可自由定制。

许可与来源

  • 许可证:自研原创 —— 粤喵自研原创,可免费用于个人与商业项目,无需署名。查看来源公示与许可清单
  • 来源:粤喵团队原创自研(从效果思路到代码实现均为独立完成,未直接复制第三方代码)
  • 首次发布:2026-09-01 · 最近更新:2026-09-01
  • 修改日志:2026-09-01 首次发布;2026-09-13 补充许可证与来源标注、复制按钮说明与法务页入口
  • 纠错联系页面 / min@cactus.asia,2 个工作日内核实处理

常见问题

这个组件可以商用吗?

可以。本组件为粤喵自研原创,可免费用于个人和商业项目,无需署名。

浏览器兼容性如何?

支持所有现代浏览器(Chrome / Firefox / Safari / Edge 最新版本)。旧版 IE 不支持 CSS 动画相关特性。

怎么修改动画参数?

直接调整 CSS 中的 animation-duration(时长)、animation-timing-function(缓动曲线)等属性即可,代码中有注释说明。

✍️ 作者与审核