纯CSS时钟必须用--seconds、--minutes、--hours变量,因CSS无运行时计算能力,需JS每秒更新变量值驱动指针旋转;变量是CSS与JS通信的唯一通道,确保三针数学关系精确。

为什么纯CSS时钟必须用 --seconds、--minutes、--hours 变量
因为CSS本身没有运行时计算能力,无法读取系统时间;但浏览器能每秒重绘一次动画帧,只要让 @keyframes 依赖 CSS 变量,再由 JS 每秒更新变量值,指针就能“动起来”。不用变量的话,只能写死旋转角度,无法实时响应。
关键点在于:CSS 只负责“怎么转”,JS 负责“转多少”——变量是两者唯一的通信通道。
-
--seconds存的是 0–59 的整数,对应秒针每秒走 6°(360° ÷ 60) -
--minutes同理是 0–59,但分针还要叠加小时带来的偏移(比如 2:30 时,分针在 180°,但时针已在 75°) -
--hours要换算成 0–11,且需包含分钟带来的小数偏移(hours + minutes/60)
指针旋转的 transform 写法必须用 rotate() 而非 rotateZ()
虽然两者视觉效果一致,但 rotate() 是 rotateZ() 的简写,在 CSS 变量插值时更稳定。某些旧版 Safari 对 rotateZ(calc(...)) 解析失败,直接卡住动画。
正确写法是:transform: rotate(calc(var(--seconds) * 6deg));
- 秒针:乘以 6(每秒 6°)
- 分针:乘以 6,再加
var(--seconds) * 0.1(每秒让分针多走 0.1°,即 6°/60) - 时针:先算
(var(--hours) % 12) * 30(每小时 30°),再加var(--minutes) * 0.5(每分钟 0.5°)
JS 更新变量时容易漏掉的两个精度问题
直接用 new Date().getSeconds() 拿到的值是整数,但分针和时针需要小数——否则指针会“跳变”,不平滑。
- 用
new Date().getTime() % 1000算毫秒偏移,除以 1000 得到秒级小数(如 23.456) - 更新
--seconds时只取整数部分,但计算分针/时针要用完整小数值 - 别用
setInterval(fn, 1000)——它不准,实际间隔可能 998ms 或 1003ms,累积误差明显;改用requestAnimationFrame驱动,按帧同步更新
兼容性陷阱:Firefox 不支持在 @keyframes 中使用 calc() + CSS 变量
Firefox 直到 v115 才完全支持该组合,低版本会忽略整个 transform 声明,指针不动。绕过方法只有一个:不用 @keyframes,全部用 JS 控制 style.transform。
但更轻量的解法是降级为静态变量更新:
- 给指针元素设
transition: transform 0.3s cubic-bezier(0.2, 0, 0.2, 1); - 每次 JS 更新变量后,指针靠 transition 自动补间,视觉上依然平滑
- 这样既避开 Firefox 的
@keyframesbug,又不需要手动写 transform 字符串
真正麻烦的不是怎么让它转,而是怎么让三根指针在任意时刻都保持数学关系正确——少算一个 /60,12 点一过,时针就漂了。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











