2019-03-27 | UNLOCK

时钟

译者注:本文内容为 Clocks - CSS Animation 的译文

译者在编写文章过程中写了 一份最终效果(iOS7 风格)源代码 供大家参考

时钟

这是关于时间的。在本文中,我们将接受创建和设置时钟动画的挑战,使用简单的CSS动画和JavaScript来触发它们。

这是我们使用HTML,CSS,SVG背景和一些JavaScript创建的时钟。我们将使用CSS动画或过渡进行任何移动,并依靠JavaScript来设置初始时间并添加基本的CSS变换。

1

HTML

要开始使用,我们需要一些HTML。

1
2
3
4
5
6
7
8
9
10
11
<article class="clock">
<div class="hours-container">
<div class="hours"></div>
</div>
<div class="minutes-container">
<div class="minutes"></div>
</div>
<div class="seconds-container">
<div class="seconds"></div>
</div>
</article>

我最初的方法是为每只指针使用三个元素。然后我回去把每个包装在一个容器元素中。虽然简单的HTML可以用于基本的CSS动画,但是当我们想要定位指针并为它们制作动画时,我们还需要包含元素。

钟面

我们将从一个基本的时钟设计开始,圆脸,简单的小时,分钟和秒针。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
.clock {
border-radius: 50%;
background: #fff url(/images/posts/clocks/ios_clock.svg) no-repeat center;
background-size: 88%;
height: 20em;
padding-bottom: 31%;
position: relative;
width: 20em;
}

.clock.simple:after {
background: #000;
border-radius: 50%;
content: "";
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
width: 5%;
height: 5%;
z-index: 10;
}

你可以在这里获得SVG背景。我还添加了一个伪元素来向中心添加一个纯黑色圆圈。然后可以根据需要将时钟的指针放在该伪元素后面。

我们现在应该有这样的结果。

2

在添加指针之前,我们需要放置容器。

1
2
3
4
5
6
7
.minutes-container, .hours-container, .seconds-container {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
}

这会将每个容器堆叠在时钟之上。接下来我们创造指针。

时针

每只指针都被赋予absolute属性值并放置在十二点钟位置。我们将从时针开始。

1
2
3
4
5
6
7
8
9
.hours {
background: #000;
height: 20%;
left: 48.75%;
position: absolute;
top: 30%;
transform-origin: 50% 100%;
width: 2.5%;
}

我正在使用百分比来简化时钟缩放。这是一项复杂的工作,但能让它们更容易适应视图或缩小手机。我们还将transform-origin属性设置为指针的底部,以便以后可以旋转。

3

分针

分针跟时针类似,但更长更细。

1
2
3
4
5
6
7
8
9
.minutes {
background: #000;
height: 40%;
left: 49%;
position: absolute;
top: 10%;
transform-origin: 50% 100%;
width: 2%;
}

4

秒针

秒针再次变细,但也进一步向下设置,使其比中心延伸得更远。为此,transform-origin为80%。这使得20%的手伸出中心。

1
2
3
4
5
6
7
8
9
10
.seconds {
background: #000;
height: 45%;
left: 49.5%;
position: absolute;
top: 14%;
transform-origin: 50% 80%;
width: 1%;
z-index: 8;
}

5

动画

停止的时钟每天只能正确两次。让我们添加一些动画来让时钟表现得更像真实的东西。

有些时钟会随着每秒跳跃,通常会产生滴答声。有些时钟会随着手的平稳移动而发出呜呜声。我们两个都试试。首先,我们会让双手平稳移动。

我们可以使用一个keyframe来指示手在360度左右移动(暗示0%的起始位置)。

1
2
3
4
5
@keyframes rotate {
100% {
transform: rotateZ(360deg);
}
}

如果使用animation属性应用于元素,则此关键帧会告诉元素在360度左右设置动画。我们将在指针上使用linear计时功能,使指针平稳移动。

1
2
3
4
5
6
7
8
9
.hours-container {
animation: rotate 43200s infinite linear;
}
.minutes-container {
animation: rotate 3600s infinite linear;
}
.seconds-container {
animation: rotate 60s infinite linear;
}

时针设置为每12小时(43,400秒)旋转一次。分针每小时旋转一次,秒针每分钟旋转一次。

把它放在一起,我们现在有运动!

6

如果你的眼睛非常敏锐,你甚至可以让分针移动。它需要一个小时才能完成一个旋转,十二个小时的时间来完成它的循环。

秒针需要60秒,因此更容易注意到。

添加停顿

通过让秒针在60个单独的动作中全天候移动,我们可以让指针更像普通时钟。实现此目的的一种简单方法是使用steps计时功能。然后每只指针的animation属性变为:

1
2
3
4
5
6
.minutes-container {
animation: rotate 3600s infinite steps(60);
}
.seconds-container {
animation: rotate 60s infinite steps(60);
}

分针和秒针现在分六步走动。浏览器会自动计算这60个步骤中的每个步骤移动的距离。

7

正确的时间

一切都很好,时间看起来不错,但准确度如何呢?使用一点JavaScript,我们可以让时间对我们的访问者来说是正确的。这是代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
/*
* Starts any clocks using the user's local time
* From: cssanimation.rocks/clocks
*/
function initLocalClocks() {
// Get the local time using JS
var date = new Date;
var seconds = date.getSeconds();
var minutes = date.getMinutes();
var hours = date.getHours();

// Create an object with each hand and it's angle in degrees
var hands = [
{
hand: 'hours',
angle: (hours * 30) + (minutes / 2)
},
{
hand: 'minutes',
angle: (minutes * 6)
},
{
hand: 'seconds',
angle: (seconds * 6)
}
];
// Loop through each of these hands to set their angle
for (var j = 0; j < hands.length; j++) {
var elements = document.querySelectorAll('.' + hands[j].hand);
for (var k = 0; k < elements.length; k++) {
elements[k].style.webkitTransform = 'rotateZ('+ hands[j].angle +'deg)';
elements[k].style.transform = 'rotateZ('+ hands[j].angle +'deg)';
// If this is a minute hand, note the seconds position (to calculate minute position later)
if (hands[j].hand === 'minutes') {
elements[k].parentNode.setAttribute('data-second-angle', hands[j + 1].angle);
}
}
}
}

此功能将时间(小时,分钟和秒)转换为每只指针的相应角度。然后循环遍历每只手并使用rotateZstyle.transform属性应用该角度。

这适用于除Safari或其他需要前缀的浏览器之外的大多数浏览器。为此,我们还使用了style.webkitTransform属性。

然后,将时钟设置为当前系统时间。

8

对齐秒针和分针

9

当首次在屏幕上绘制时钟时,在分针需要移动之前不到一分钟。为了实现这一点,我们可以计算出第一分钟结束的时间并手动轻推分针。由于我们使用JavaScript进行第一次移动,我们可以使用setInterval每分钟继续旋转6度。

在我们移动分针之前,我们需要告知我们当前的分钟数。您可能已经注意到这些线条。

1
2
3
if (hands[j].hand === 'minutes') {
elements[k].parentNode.setAttribute('data-second-angle', hands[j + 1].angle);
}

这些额外的行检查指针是否是“分钟”指针,如果是,则使用秒针的当前角度设置数据属性。

使用此数据属性集,我们可以使用此数据计算何时移动分针。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
/*
* Set a timeout for the first minute hand movement (less than 1 minute), then rotate it every minute after that
*/
function setUpMinuteHands() {
// Find out how far into the minute we are
var containers = document.querySelectorAll('.minutes-container');
var secondAngle = containers[0].getAttribute("data-second-angle");
if (secondAngle > 0) {
// Set a timeout until the end of the current minute, to move the hand
var delay = (((360 - secondAngle) / 6) + 0.1) * 1000;
setTimeout(function() {
moveMinuteHands(containers);
}, delay);
}
}

/*
* Do the first minute's rotation
*/
function moveMinuteHands(containers) {
for (var i = 0; i < containers.length; i++) {
containers[i].style.webkitTransform = 'rotateZ(6deg)';
containers[i].style.transform = 'rotateZ(6deg)';
}
// Then continue with a 60 second interval
setInterval(function() {
for (var i = 0; i < containers.length; i++) {
if (containers[i].angle === undefined) {
containers[i].angle = 12;
} else {
containers[i].angle += 6;
}
containers[i].style.webkitTransform = 'rotateZ('+ containers[i].angle +'deg)';
containers[i].style.transform = 'rotateZ('+ containers[i].angle +'deg)';
}
}, 60000);
}

添加弹跳

由于我们现在使用JavaScript来移动分针,我们应该删除动画属性。我们可以用过渡替换它,而不是简单地删除它。这是一个为动画添加更多角色的机会。

当JavaScript为手设置新角度时,元素上的CSS转换将告诉浏览器为此新位置设置动画。这意味着JavaScript只处理简单的角度变化,浏览器可以处理它的动画。

在我们这样做之前,我们应该更新代码以使用JavaScript来移动秒针。让我们使用此代码为秒针容器设置动画,每分钟动画60次。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/*
* Move the second containers
*/
function moveSecondHands() {
var containers = document.querySelectorAll('.seconds-container');
setInterval(function() {
for (var i = 0; i < containers.length; i++) {
if (containers[i].angle === undefined) {
containers[i].angle = 6;
} else {
containers[i].angle += 6;
}
containers[i].style.webkitTransform = 'rotateZ('+ containers[i].angle +'deg)';
containers[i].style.transform = 'rotateZ('+ containers[i].angle +'deg)';
}
}, 1000);
}

通过JavaScript处理秒针和分针,更新CSS以使用transitions替换animation属性。

1
2
3
4
5
6
.minutes-container {
transition: transform 0.3s cubic-bezier(.4,2.08,.55,.44);
}
.seconds-container {
transition: transform 0.2s cubic-bezier(.4,2.08,.55,.44);
}

这些转换适用于transform属性并使用cubic-bezier定时函数。这个计时功能让秒针有些反弹。

10

iOS7 风格

我非常喜欢Apple iOS 7中使用的时钟的简单性。他们已经伸长了指针,但我更喜欢较短的版本。

通过设计针部样式并添加带有数字的背景图像,我们可以轻松创建此外观。

11

这种设计本身就是Hans Hilfiker对瑞士铁路时钟的演变。通过改变一些样式并添加新的背景图像,我们可以使我们的时钟适应这种风格。

如果您想出其他设计,请告诉我。

使用 Moment.js

我计划这篇文章的第一个想法之一是重建酒店钟表场景,三个时钟显示不同的时区。

调整不同时区的最简单方法是使用令人惊叹的Moment.js 时区库

12

您可以在此Codepen上查看代码。

浏览器兼容性

现代浏览器可以处理所涉及的CSS过渡和动画。 IE10 +,最近的Chrome和Firefox支持它们没有前缀,Safari需要-webkit前缀。

不要忘记在JavaScript中使用前缀属性。

(完)

css

评论加载中