乐趣区

关于前端:还在使用定时器吗CSS-也能实现电子时钟

通常要做一个时钟,必定离不开 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 定义后,这个变量自身能够独自设置过渡了,而不再取决于一些仅反对过渡的属性(colorwidth等)。甚至还能加上动画,须要用到 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*2460s*6060s,具体实现如下:

@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 常识和技巧,简略总结一下吧

  1. CSS 实现实质是有限循环的 CSS 动画
  2. 灵活运用 CSS calc 计算
  3. CSS 计数器能够将 CSS 变量通过 content 显示在页面
  4. 数字的变动当初能够通过 CSS @property 配合动画实现
  5. 时分秒的区别在于各自的动画时长、动画起始点不同
  6. CSS 主动补零能够参考之前的文章,这里采纳 decimal-leading-zero 实现
  7. 工夫初始化其实就是指定动画 delay 值
  8. 指定初始值时还须要思考到各自的偏移量,例如 19:30:30,此时的时针数字其实是 30.5
  9. 分隔符的闪动动画

其实整个实现过程就是一个一直思考、学习的过程,比方为了实现数字的变动,就必须去学习 @property 相干,为了实现补零,就须要去理解更深层次的计数器相干,还有用到的各种动画。最初,如果感觉还不错,对你有帮忙的话,欢送点赞、珍藏、转发❤❤❤

退出移动版