时钟——CSS 动画

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

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

时钟

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

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

HTML

要开始使用,咱们须要一些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);
        }
    }
  }
}
复制代码

此功能将时间(小时,分钟和秒)转换为每只指针的相应角度。而后循环遍历每只手并使用rotateZstyle.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定时函数。这个计时功能让秒针有些反弹。

iOS7 风格

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

经过设计针部样式并添加带有数字的背景图像,咱们能够轻松建立此外观。

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

若是您想出其余设计,请告诉我。

使用 Moment.js

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

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

您能够在此Codepen上查看代码。

浏览器兼容性

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

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

(完)

本文做者 Thinker

本文若有错误之处,请留言,我会及时更正

以为对您有帮助的话就点个赞收藏吧!

欢迎转载或分享,转载时请注明出处

阅读原文

相关文章
相关标签/搜索