纯 CSS 实现一个计时器

开发 前端
CSS 现在可不仅仅只是改一个颜色这么简单,还可以做很多交互,比如做一个功能齐全的计时器?

CSS 现在可不仅仅只是改一个颜色这么简单,还可以做很多交互,比如做一个功能齐全的计时器?

图片

样式上并不复杂,主要是几个交互的地方

  1. 数字时钟的变化
  2. 开始、暂停操作
  3. 重置操作

如何仅使用 CSS 来实现这样的功能呢?一起看看吧

一、数字时钟的变化

这里简单介绍一下实现原理。

在以前,如果要实现数字的递增变化,可能需要提前准备好这些数字,例如像这样。

<span>
<i>1</i>
<i>2</i>
...
<i>59</i>
</span>

或者用伪元素创建也行。

span::before{
content: '1\A 2\A 3\A ... 59'
}

这种方式需要创建多个标签,略微繁琐,也不易扩展。现在有更简洁的方式可以实现了,那就是 CSS @property[2]。这是干什么的呢?简单来讲,可以自定义属性,在这个例子中,可以让数字像颜色一样进行过渡和动画,可能不太懂,直接看例子吧

假设 HTML 是这样的。

<span style="--num: 0"></span>

我们让这个自定义变量在页面中展示出来,单纯的 content无法直接显示自定义变量,需要借助计数器,有兴趣的可以参考这篇文章:小tips: 如何借助content属性显示CSS var变量值[3]

span::after{
counter-reset: num var(--num);
content: counter(num);
}

图片

现在可以通过:hover改变这个数字。

span:hover::after{
--num: 59
}

图片

很生硬的从 0 变成 59 了,非常符合常规,因为--num​并不支持过渡动画。如果利用 CSS property,情况就不一样了,需要改造的地方很少,先定义一下--num,然后给这个变量一个过渡时间,如下:

@property --num { 
syntax: '<integer>';
inherits: false;
initial-value: 0;
}
span::after{
transition: 1s --num;
}

神奇的一幕发生了。

图片

看着好像不可思议?可以这么理解,通过@property定义后,这个变量本身可以单独设置过渡了,而不再取决于一些仅支持过渡的属性(color、width等)。还可以使用动画,如下:

@keyframes num {
to {
--num: 10
}
}
span{
animation: num 1s infinite steps(10);
}

数字变化的基本原理就是这样了,一个无限循环的 CSS 动画!

图片

回到这里,这里需要的是一个秒表,分为“分”、“秒”、“毫秒”(这里的毫秒就用 1/100秒来代替),3个数字的动画时长都不一致,所以需要定义3个 CSS 变量,完整实现如下:

@keyframes minitus {
to {
--m: 59
}
}
@keyframes seconds {
to {
--s: 59
}
}
@keyframes ms {
to {
--ms: 99
}
}
span{
counter-reset: minitus var(--m) seconds var(--s) ms var(--ms);
animation: minitus 3600s infinite steps(60, end),
seconds 60s infinite steps(60, end),
ms 1s infinite steps(100, end);
}
span::before{
content: counter(minitus, decimal-leading-zero) ':' counter(seconds, decimal-leading-zero) ':' counter(ms, decimal-leading-zero);
}

这样就得到了一个自动运行的秒表。

图片

二、开始、暂停操作

首先思考一下,CSS 需要怎样记住点击操作?答案就是input type="checkbox"(通过label关联),可以这样来布局。

<div class="counter">
<input type="checkbox" id="start" hidden>
<label class="btn start" for="start"></label>
<label class="btn reset">重置</label>
<div class="clock"></div>
</div>

因为需要通过input:cheked来控制秒表的状态,需要借助后置兄弟选择器~来实现,所以input需要在前面(当然,现在有了:has也可以不需要这样)。

这里可以通过grid布局来灵活摆放各个模块的位置。

.counter{
display: grid;
grid-template-areas:
"clock clock"
"start reset"
}
.start{
/**/
grid-area: start;
}
.reset{
/**/
grid-area: reset;
}

简单美化以后,可以得到这样的效果:

图片

然后,由于秒表的运行其实就是一个 CSS 动画,所以我们可以直接用:cheked来控制动画的状态,默认设置成暂停的,还有按钮文字也可以通过::before来生成,实现如下:

.clock{
animation-play-state: paused;/*默认暂停*/
}
.start::before{
content: '开始';
}
:checked~.start::before{
content: '暂停';
}
:checked~.clock{
animation-play-state: running;
}

这样就可以通过按钮手动控制开始和暂停了

图片

三、重置操作

重置看起来好像有点麻烦,有点无从下手。

其实重置一个动画非常简单,直接将动画取消就可以了,也就是相当于重置了动画,如下:

.reset:active+.clock{
animation: none;
}

其次,重置一般只有在暂停时才可用,所以还需要用前面的:checked禁用一下,并且视觉上可以透明度降低一点,实现如下:

:checked~.reset{
opacity: .65;
pointer-events: none;
}

这样就得到了文章开头所示的效果:

图片

当然,你还可以使用自定义字体,比如DigitalNumbers。

图片

完整代码可以查看以下任意链接:

  • CSS counter (juejin.cn)[4]
  • CSS counter (codepen.io)[5]
  • CSS counter (runjs.work)[6]

四、会影响业务逻辑吗?

还有一点,有同学担心 CSS 只是视觉层面的,可能会影响业务逻辑。

图片

确实,由于是伪元素渲染,页面上看不到任何数字,也就是无法直接通过innerText获取当前时间,但是,我们可以借助getComputedStyle来得到 CSS 变量。

getComputedStyle($0).getPropertyValue('--ms')

实时获取如下:

图片

所以通过 CSS 方式也是完全不影响业务逻辑的。

五、兼容性和总结

由于在实现中用到了CSS @property特性,这是CSS Houdini的一部分,目前只有 Chrome 支持(可惜了😥)。让人惊奇的是,Safari居然在前不久也支持了这个特性,未来可期,如下:

图片

当然这不是重点,只是这种方式实现更加简洁而已,完全可以用传统方式来实现,有兴趣的可以尝试一下。

下面总结一下实现要点

  1. CSS 现在很强大,不仅仅只是样式,还能做很多交互。
  2. CSS @property 可以使CSS变量支持动画。
  3. 数字时钟的变化其实是一个CSS变量不断递增循环的动画。
  4. CSS 点击操作状态可以通过:checked控制。
  5. Grid 布局可以很方便的控制各个元素的位置。
  6. 计时器开始和暂停其实就是动画的运行和暂停。
  7. 直接将动画取消就相当于重置了整个动画。

参考资料

[1]还在使用定时器吗?CSS 也能实现电子时钟: https://juejin.cn/post/7083339388511322143​。

[2]CSS @property: https://developer.mozilla.org/zh-CN/docs/Web/CSS/@property​。

[3]小tips: 如何借助content属性显示CSS var变量值: https://link.juejin.cn?target=https%3A%2F%2Fwww.zhangxinxu.com%2Fwordpress%2F2019%2F05%2Fcontent-css-var%2F​。

[4]CSS counter (juejin.cn): https://code.juejin.cn/pen/7221511863551410237​。

[5]CSS counter (codepen.io):  

[6]CSS counter (runjs.work): https://runjs.work/projects/6d3305ab2de14840​。

责任编辑:姜华 来源: 前端侦探
相关推荐

2020-06-11 08:48:49

JavaScript开发技术

2022-06-28 15:29:56

Python编程语言计时器

2022-06-19 20:48:06

树莓派Linux

2013-05-23 16:01:47

Android开发移动开发Chronometer

2024-03-13 08:21:53

冒泡排序动画

2012-05-08 13:58:37

SharePoint

2011-05-31 16:50:35

Android 线程

2023-01-11 09:02:50

2021-11-26 00:04:20

Go计时器重构

2011-09-08 14:01:01

Android Wid实例

2013-03-25 10:03:35

网络优化网络抑制快速认知网络

2023-12-11 09:50:35

Linux定时器

2010-01-05 15:00:30

.NET Framew

2010-01-25 11:29:33

Android计时器

2022-06-23 07:23:34

自定义组件计时器

2020-03-10 09:42:04

JavaScript前端线程

2023-05-22 09:10:53

CSSloading 效

2021-10-19 22:23:47

CSSBeautiful按钮

2016-11-01 09:46:04

2022-02-21 07:02:16

CSSbeautiful按钮
点赞
收藏

51CTO技术栈公众号