纯 CSS 实现秒表:零 JavaScript 的计时器
利用 CSS @property 和 counter-reset 打造无需脚本的精密计时器
Live Demo
实现原理
这个秒表的核心魔法在于 CSS 的 @property 规则。它允许我们定义自定义属性,并指定其语法、继承性和初始值。结合 counter-reset 和 animation,我们可以在不借助 JavaScript 的情况下实现精确的时间计数。
💡 关键技术点
@property 是 CSS Houdini API 的一部分,它让我们能够像定义原生 CSS 属性一样定义自定义属性,包括指定数据类型(如 <integer>),这使得动画插值成为可能。
1. 定义计数器属性
首先,我们需要为每个时间位(分、秒、毫秒)定义可动画的整数属性:
CSS
@property --ms-tens {
initial-value: 0;
inherits: false;
syntax: '<integer>';
}
@property --ms-singles {
initial-value: 0;
inherits: false;
syntax: '<integer>';
}2. 创建计数动画
使用 @keyframes 定义每个数字从 0 到最大值的变化:
CSS
@keyframes ms-singles {
to { --ms-singles: 10; }
}
@keyframes s-singles {
to { --s-singles: 10; }
}3. 配置数字显示
每个数字元素使用 counter-reset 将自定义属性值转换为计数器,然后通过 ::after 伪元素的 content 属性显示:
CSS
.digit {
position: relative;
color: transparent;
counter-reset: var(--counter-name) var(--counter-variable);
animation: var(--name, none) var(--duration, 1s)
infinite steps(var(--steps)) var(--state);
}
.digit:after {
content: counter(var(--counter-name));
font-variant: tabular-nums;
color: var(--digit);
position: absolute;
bottom: 0;
right: 0;
}时间精度控制
每个时间位有不同的动画周期,通过精确计算实现正确的时间流逝:
| 时间位 | 动画周期 | 步数 | 说明 |
|---|---|---|---|
| 毫秒个位 | 0.1s | 10 | 每 100ms 变化一次 |
| 毫秒十位 | 1s | 10 | 每秒变化一次 |
| 秒个位 | 10s | 10 | 每 10 秒循环 |
| 秒十位 | 60s | 6 | 每 60 秒循环 |
| 分钟个位 | 600s | 10 | 每 10 分钟循环 |
| 分钟十位 | 3600s | 6 | 每 60 分钟循环 |
状态控制机制
使用隐藏的 checkbox 和 CSS 兄弟选择器实现开始/暂停/重置功能:
CSS
/* 开始状态 */
#start:checked ~ .stopwatch__content {
--state: running;
}
/* 暂停状态 */
#pause:checked ~ .stopwatch__content {
--state: paused;
}浏览器兼容性
@property 规则目前已被所有现代浏览器支持(Chrome 85+、Firefox 128+、Safari 16.4+)。对于旧版浏览器,可以提供一个静态回退方案。
总结
通过 @property、counter-reset 和 animation 的组合,我们实现了一个完全不需要 JavaScript 的秒表。这种技术展示了 CSS 的强大能力,也为那些追求极致性能或需要在禁用 JavaScript 环境下工作的场景提供了解决方案。
评论