译者注:本文内容为 Clocks - CSS Animation 的译文javascript
译者在编写文章过程当中写了 一份最终效果(iOS7 风格)源代码 供你们参考css
这是关于时间的。在本文中,咱们将接受建立和设置时钟动画的挑战,使用简单的CSS动画和JavaScript来触发它们。html
这是咱们使用HTML,CSS,SVG背景和一些JavaScript建立的时钟。咱们将使用CSS动画或过渡进行任何移动,并依靠JavaScript来设置初始时间并添加基本的CSS变换。java
要开始使用,咱们须要一些HTML。ios
<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动画,可是当咱们想要定位指针并为它们制做动画时,咱们还须要包含元素。git
咱们将从一个基本的时钟设计开始,圆脸,简单的小时,分钟和秒针。github
.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背景。我还添加了一个伪元素来向中心添加一个纯黑色圆圈。而后能够根据须要将时钟的指针放在该伪元素后面。web
咱们如今应该有这样的结果。浏览器
在添加指针以前,咱们须要放置容器。less
.minutes-container, .hours-container, .seconds-container {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
}
复制代码
这会将每一个容器堆叠在时钟之上。接下来咱们创造指针。
每只指针都被赋予absolute
属性值并放置在十二点钟位置。咱们将从时针开始。
.hours {
background: #000;
height: 20%;
left: 48.75%;
position: absolute;
top: 30%;
transform-origin: 50% 100%;
width: 2.5%;
}
复制代码
我正在使用百分比来简化时钟缩放。这是一项复杂的工做,但能让它们更容易适应视图或缩小手机。咱们还将transform-origin
属性设置为指针的底部,以便之后能够旋转。
分针跟时针相似,但更长更细。
.minutes {
background: #000;
height: 40%;
left: 49%;
position: absolute;
top: 10%;
transform-origin: 50% 100%;
width: 2%;
}
复制代码
秒针再次变细,但也进一步向下设置,使其比中心延伸得更远。为此,transform-origin
为80%。这使得20%的手伸出中心。
.seconds {
background: #000;
height: 45%;
left: 49.5%;
position: absolute;
top: 14%;
transform-origin: 50% 80%;
width: 1%;
z-index: 8;
}
复制代码
中止的时钟天天只能正确两次。让咱们添加一些动画来让时钟表现得更像真实的东西。
有些时钟会随着每秒跳跃,一般会产生滴答声。有些时钟会随着手的平稳移动而发出呜呜声。咱们两个都试试。首先,咱们会让双手平稳移动。
咱们可使用一个keyframe
来指示手在360度左右移动(暗示0%的起始位置)。
@keyframes rotate {
100% {
transform: rotateZ(360deg);
}
}
复制代码
若是使用animation
属性应用于元素,则此关键帧会告诉元素在360度左右设置动画。咱们将在指针上使用linear
计时功能,使指针平稳移动。
.hours-container {
animation: rotate 43200s infinite linear;
}
.minutes-container {
animation: rotate 3600s infinite linear;
}
.seconds-container {
animation: rotate 60s infinite linear;
}
复制代码
时针设置为每12小时(43,400秒)旋转一次。分针每小时旋转一次,秒针每分钟旋转一次。
把它放在一块儿,咱们如今有运动!
若是你的眼睛很是敏锐,你甚至可让分针移动。它须要一个小时才能完成一个旋转,十二个小时的时间来完成它的循环。
秒针须要60秒,所以更容易注意到。
经过让秒针在60个单独的动做中全天候移动,咱们可让指针更像普通时钟。实现此目的的一种简单方法是使用steps
计时功能。而后每只指针的animation
属性变为:
.minutes-container {
animation: rotate 3600s infinite steps(60);
}
.seconds-container {
animation: rotate 60s infinite steps(60);
}
复制代码
分针和秒针如今分六步走动。浏览器会自动计算这60个步骤中的每一个步骤移动的距离。
一切都很好,时间看起来不错,但准确度如何呢?使用一点JavaScript,咱们可让时间对咱们的访问者来讲是正确的。这是代码:
/* * 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);
}
}
}
}
复制代码
此功能将时间(小时,分钟和秒)转换为每只指针的相应角度。而后循环遍历每只手并使用rotateZ
的style.transform
属性应用该角度。
这适用于除Safari或其余须要前缀的浏览器以外的大多数浏览器。为此,咱们还使用了style.webkitTransform
属性。
而后,将时钟设置为当前系统时间。
当首次在屏幕上绘制时钟时,在分针须要移动以前不到一分钟。为了实现这一点,咱们能够计算出第一分钟结束的时间并手动轻推分针。因为咱们使用JavaScript进行第一次移动,咱们可使用setInterval
每分钟继续旋转6度。
在咱们移动分针以前,咱们须要告知咱们当前的分钟数。您可能已经注意到这些线条。
if (hands[j].hand === 'minutes') {
elements[k].parentNode.setAttribute('data-second-angle', hands[j + 1].angle);
}
复制代码
这些额外的行检查指针是不是“分钟”指针,若是是,则使用秒针的当前角度设置数据属性。
使用此数据属性集,咱们可使用此数据计算什么时候移动分针。
/* * 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次。
/* * 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
属性。
.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
定时函数。这个计时功能让秒针有些反弹。
我很是喜欢Apple iOS 7中使用的时钟的简单性。他们已经伸长了指针,但我更喜欢较短的版本。
经过设计针部样式并添加带有数字的背景图像,咱们能够轻松建立此外观。
这种设计自己就是Hans Hilfiker对瑞士铁路时钟的演变。经过改变一些样式并添加新的背景图像,咱们可使咱们的时钟适应这种风格。
若是您想出其余设计,请告诉我。
我计划这篇文章的第一个想法之一是重建酒店钟表场景,三个时钟显示不一样的时区。
调整不一样时区的最简单方法是使用使人惊叹的Moment.js 时区库。
您能够在此Codepen上查看代码。
现代浏览器能够处理所涉及的CSS过渡和动画。 IE10 +,最近的Chrome和Firefox支持它们没有前缀,Safari须要-webkit
前缀。
不要忘记在JavaScript中使用前缀属性。
(完)
本文做者 Thinker
本文若有错误之处,请留言,我会及时更正
以为对您有帮助的话就点个赞或收藏吧!
欢迎转载或分享,转载时请注明出处