通常要做一个时钟,必定离不开 JS 定时器。明天换一种思路,用 CSS 来实现一个时钟,如下:
你也能够拜访这个CSS time (codepen.io)查看实际效果
当然借用了一点点 JS 用于初始化工夫,整个时钟的运行都是由 CSS 实现的,有很多你可能不晓得的小技巧,一起看看吧
一、数字的变换
先看看数字是如何变换的。
在以前,如果要实现数字的递增变动,可能须要提前准备好这些数字,例如像这样
<span> <i>1</i> <i>2</i> ... <i>59</i></span>而后通过扭转位移来实现。
然而,当初有更简洁的形式能够实现了,那就是 CSS @property,不理解这个的能够参考这篇文章:CSS @property,让不可能变可能。这是干什么的呢?简略来讲,能够自定义属性,在这个例子中,能够让数字像色彩一样进行过渡和动画,可能不太懂,间接看例子吧
假如 HTML 是这样的
<span style="--num: 0"></span>咱们让这个自定义变量在页面中展现进去,单纯的 content无奈间接显示自定义变量,须要借助定时器,有趣味的能够参考这篇文章:小tips: 如何借助content属性显示CSS var变量值
span::after{ counter-reset: num var(--num); content: counter(num);}而后,能够通过:hover扭转这个数字
span:hover::after{ --num: 59}很僵硬的从 0 变成 59 了,十分合乎惯例。如果利用 CSS property,状况就不一样了,须要革新的中央很少,先定义一下--h,而后给这个变量一个过渡工夫,如下
@property --h { syntax: '<integer>'; inherits: false; initial-value: 0;}span::after{ transition: 1s --num;}神奇的一幕产生了
看着如同不堪设想?能够这么了解,通过@property定义后,这个变量自身能够独自设置过渡了,而不再取决于一些仅反对过渡的属性(color、width等)。甚至还能加上动画,须要用到steps办法,设置动画周期为有限,如下
@keyframes num { to { --num: 10 }}span{ animation: num 1s infinite steps(10);}时钟的根本运行原理就是这样了,一个有限循环的 CSS 动画!
二、时、分、秒
上面来看具体时、分、秒的实现,HTML 如下
<div class="time"> <span class="hour"></span> <a class="split">:</a> <span class="minitus"></span> <a class="split">:</a> <span class="seconds"></span></div>给时、分、秒附上初始值
@property --h { syntax: '<integer>'; inherits: false; initial-value: 0;}@property --m { syntax: '<integer>'; inherits: false; initial-value: 0;}@property --s { syntax: '<integer>'; inherits: false; initial-value: 0;}.hour::after{ counter-reset: hour var(--h); content: counter(hour);}.minitus::after{ counter-reset: minitus var(--m); content: counter(minitus);}.seconds::after{ counter-reset: seconds var(--s); content: counter(seconds);}这里的时、分、秒并没有联动关系,所以各自都须要独自的动画。上面就须要思考一下,如果用 CSS 动画来实现,每个的动画起始点和时长是多少呢?
没错,就是你想的,时针是0-23,时长24h,分针是0-59,时长60min,秒针是0-59,时长60s,然而 CSS 中的工夫单位只反对秒(s)或者毫秒(ms),所以这里须要转换一下,时长别离是60s*60*24、60s*60、60s,具体实现如下:
@keyframes hour { to { --h: 24 }}@keyframes minitus { to { --m: 60 }}@keyframes seconds { to { --s: 60 }}.hour::after{ counter-reset: hour var(--h); content: counter(hour); animation: hour calc(60s * 60 * 24) infinite steps(24);}.minitus::after{ counter-reset: minitus var(--m); content: counter(minitus); animation: minitus calc(60s * 60) infinite steps(60);}.seconds::after{ counter-reset: seconds var(--s); content: counter(seconds); animation: seconds 60s infinite steps(60);}这里为了便于察看,将工夫调快了10倍(60s => 6s),如下
三、时、分、秒主动补零
下面的布局有个问题,1 位数和 2 位数宽度变动导致时钟整体都在“晃动”,所以须要在1位数时补上一个“0”。对于 CSS 补零,之前在这篇文章中提到了 3 种计划,因为这里用了计数器,所以间接抉择更改计数器款式的办法,通过decimal-leading-zero来实现,具体做法如下
.hour::after{ /**/ content: counter(hour, decimal-leading-zero);/*增加计数器款式*/}这样就谐和多了
四、工夫初始化
方才都从00:00:00开始了,所以须要手动指定一下初始工夫。假如当初是19:26:30,如何初始化呢?
这里须要用animation-delay来提前静止到将来指定地位,为了不便管制,应用三个变量--dh、--dm、--ds来示意初始工夫,留神,因为animation-delay也只反对秒(s)或者毫秒(ms),所以也同样须要转换,实现如下
:root{ --dh: 19; --dm: 26; --ds: 30;}.hour::after{ /**/ animation: hour calc(60s * 60 * 24) infinite steps(24); animation-delay: calc( -60s * 60 * var(--dh) );}.minitus::after{ /**/ animation: minitus calc(60s * 60) infinite steps(60); animation-delay: calc( -60s * var(--dm) );}.seconds::after{ /**/ animation: seconds 60s infinite steps(60); animation-delay: calc( -1s * var(--ds) );}是不是有点奇怪?分钟在秒钟走到 30 的时候才变动,晚了半分钟。起因是这样的,尽管从数字上看,分钟是 26,然而还要思考到秒钟的静止状况,比方像这种状况,分钟其实曾经走了一半,应该是26.5(26 + 30 / 60),所以在计算时还须要加上偏移量。上面咱们通过 JS 获取实在的工夫,并修复偏移
const d = new Date()const h = d.getHours();const m = d.getMinutes();const s = d.getSeconds();document.body.style.setProperty('--ds', s)document.body.style.setProperty('--dm', m + s/60)document.body.style.setProperty('--dh', h + m/60 + s/3600)这样就失常了
五、闪动的分隔符
为了时钟看起来更加“动感”,能够给分隔符加上闪动动画,代码如下
@keyframes shark { 0%, 100%{ opacity: 1; } 50%{ opacity: 0; }}.split{ animation: shark 1s step-end infinite;}当初看下最终的成果
残缺代码能够拜访 CSS time (codepen.io)
六、总结一下
想不到实现一个时钟成果,用到了那么多 CSS 常识和技巧,简略总结一下吧
- CSS 实现实质是有限循环的 CSS 动画
- 灵活运用 CSS calc 计算
- CSS 计数器能够将 CSS 变量通过 content 显示在页面
- 数字的变动当初能够通过 CSS @property 配合动画实现
- 时分秒的区别在于各自的动画时长、动画起始点不同
- CSS 主动补零能够参考之前的文章,这里采纳 decimal-leading-zero 实现
- 工夫初始化其实就是指定动画 delay 值
- 指定初始值时还须要思考到各自的偏移量,例如 19:30:30,此时的时针数字其实是 30.5
- 分隔符的闪动动画
其实整个实现过程就是一个一直思考、学习的过程,比方为了实现数字的变动,就必须去学习 @property 相干,为了实现补零,就须要去理解更深层次的计数器相干,还有用到的各种动画。最初,如果感觉还不错,对你有帮忙的话,欢送点赞、珍藏、转发❤❤❤