今天难得休闲,决定玩一下CSS3的动画特性,写了一个HTML+CSS3的复古时钟。
来看看最终成品:
See the Pen Dynamic Clock by liuyanghejerry (@liuyanghejerry) on CodePen.
要实现本文的时钟,需要用到许多CSS3中的高级特性,比如animation steps,keyframe、transform等。在跟随教程之前,请先确保您的浏览器支持这些特性。
HTML结构
时钟的HTML结构非常简单:
没有用任何高级的东西,都很平常。
一个静止的钟
.clock { height: 400px; width: 220px; margin: 0 auto; } .clock .body-top { height: 200px; margin: 0; padding: 0; border-radius: 400px 400px 0 0; background-color: #B28247; } .body-top .dial { height: 150px; width: 150px; margin: 0 auto; position: relative; -webkit-transform: translateY(30px); transform: translateY(30px); border-radius: 200px; background-color: #C9BC9C; } .dial .second-hand { height: 74px; width: 10px; border-radius: 20px; position: absolute; z-index: 2; -webkit-transform: translate(70px, 75px) rotate(180deg); transform: translate(70px, 75px) rotate(180deg); -webkit-transform-origin: 50% 5px; transform-origin: 50% 5px; background-color: #7F4F21; } .dial .minute-hand { height: 70px; width: 10px; border-radius: 20px; position: absolute; z-index: 3; -webkit-transform: translate(70px, 75px) rotate(180deg); transform: translate(70px, 75px) rotate(180deg); -webkit-transform-origin: 50% 5px; transform-origin: 50% 5px; background-color: #40220F; } .dial .hour-hand { height: 50px; width: 10px; border-radius: 20px; position: absolute; z-index: 4; -webkit-transform: translate(70px, 75px) rotate(180deg); transform: translate(70px, 75px) rotate(180deg); -webkit-transform-origin: 50% 5px; transform-origin: 50% 5px; background-color: black; } .clock .body-bottom { position: relative; z-index: -1; height: 190px; margin: 0; padding: 0; border-radius: 0 0 20px 20px; background-color: #7F4F21; } .body-bottom .pendulum { height: 140px; } .pendulum .pendulum-stick { height: 70%; width: 12px; margin: 0 auto; background-color: black; } .pendulum .pendulum-body { height: 40px; width: 40px; border-radius: 40px; margin: 0 auto; margin-top: -2px; background-color: #40220F; }
一个静态的钟不难,利用`transform`(或者`top`、`left`),我们可以将时针、分针以及秒针都摆放在同一个圆心上。注意`z-index`的顺序,因为我们希望最长的指针是在最下面的,这样才能确保指针重合的时候,比如0点0分0秒,短指针不会被完全覆盖。
`.pendulum-body`中,我把`margin-top`向上偏移了一点,这样钟摆才不会脱离那根棍子(唔……)。
另外,我给三根指针都设置了`transform-origin: 50% 5px;`(好吧,写在一个单独抽象的class里也行,我就是懒的改了),这是为了保证旋转、偏移的圆心始终是指针的端点中心,如图所示:
不过请忽略我给`border-radius`写成20px,我就是以防万一……
See the Pen Static Clock by liuyanghejerry (@liuyanghejerry) on CodePen.
让钟动起来
指针
时钟指针的动画可以通过旋转来完成。CSS3的`steps()`非常好用,通过它可以把一段时间分成N等份来播放动画。比如对于秒针,秒针旋转一圈理论上应该是60秒,在这段动画里,我把旋转一圈的时间恰好等分成60份,这样每秒秒针都可以转动一次。相应地,分针、时针也按各自的旋转周期来划分。
我这儿只让秒针1秒动一次,但是实际上你可以把60秒切割成更细的粒度,比如3600份,这样秒针就看起来连续转动起来(而不是离散地)。
下面是改动后的代码:
.dial .second-hand { height: 74px; width: 10px; border-radius: 20px; position: absolute; z-index: 2; -webkit-transform-origin: 50% 5px; transform-origin: 50% 5px; animation: timehand 60s steps(60, end) infinite; -webkit-animation: timehand 60s steps(60, end) infinite; background-color: #7F4F21; } .dial .minute-hand { height: 70px; width: 10px; border-radius: 20px; position: absolute; z-index: 3; -webkit-transform-origin: 50% 5px; transform-origin: 50% 5px; animation: timehand 3600s steps(3600, end) infinite; -webkit-animation: timehand 3600s steps(3600, end) infinite; background-color: #40220F; } .dial .hour-hand { height: 50px; width: 10px; border-radius: 20px; position: absolute; z-index: 4; -webkit-transform-origin: 50% 5px; transform-origin: 50% 5px; animation: timehand 43200s steps(43200, end) infinite; -webkit-animation: timehand 43200s steps(43200, end) infinite; background-color: black; } @keyframes timehand { 0% { -webkit-transform: translate(70px, 75px) rotate(180deg); transform: translate(70px, 75px) rotate(180deg); } 100% { -webkit-transform: translate(70px, 75px) rotate(539deg); transform: translate(70px, 75px) rotate(539deg); } } @-webkit-keyframes timehand { 0% { -webkit-transform: translate(70px, 75px) rotate(180deg); transform: translate(70px, 75px) rotate(180deg); } 100% { -webkit-transform: translate(70px, 75px) rotate(539deg); transform: translate(70px, 75px) rotate(539deg); } }
钟摆
我没找到特别好的方法来真正实现单摆运动,所以只用了普通的贝塞尔曲线进行模拟,基本上可以说是凑合出来的。
.body-bottom .pendulum { height: 140px; -webkit-animation-duration: 2s; animation-duration: 2s; -webkit-animation-name: ticktock; animation-name: ticktock; -webkit-animation-iteration-count: infinite; animation-iteration-count: infinite; -webkit-animation-timing-function: cubic-bezier(0.645, 0.045, 0.355, 1.000); animation-timing-function: cubic-bezier(0.645, 0.045, 0.355, 1.000); -webkit-animation-direction: alternate; animation-direction: alternate; -webkit-animation-fill-mode: both; animation-fill-mode: both; -webkit-animation-play-state: running; animation-play-state: running; -webkit-transform-origin: 50% -70%; transform-origin: 50% -70%; }
我还写了一份SCSS的,仅供参考。
这里有点细节,旋转的原点需要向上偏移一些(`transform-origin: 50% -70%;`),超出画出的钟摆的范畴,这样钟摆看起来才更加真实。
最终结果
See the Pen Dynamic Clock by liuyanghejerry (@liuyanghejerry) on CodePen.
好了,一个有钟摆、指针按照真实世界来动的复古时钟做好了。但是这个钟还有一些瑕疵:
1、钟摆看起来不是特别自然,因为不是真正的单摆运动曲线。如果谁有什么更好的办法,记得告诉我;
2、时间总是从0开始,这个不太好,如果是实时的就好了。但我真的不想加JS进去。