時鐘——CSS 動畫

ThinkerZhang發表於2019-02-27

譯者注:本文內容為 Clocks - CSS Animation 的譯文

譯者在編寫文章過程中寫了 一份最終效果(iOS7 風格)原始碼 供大家參考

時鐘

這是關於時間的。在本文中,我們將接受建立和設定時鐘動畫的挑戰,使用簡單的CSS動畫和JavaScript來觸發它們。

這是我們使用HTML,CSS,SVG背景和一些JavaScript建立的時鐘。我們將使用CSS動畫或過渡進行任何移動,並依靠JavaScript來設定初始時間並新增基本的CSS變換。

時鐘——CSS 動畫

HTML

要開始使用,我們需要一些HTML。

<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動畫,但是當我們想要定位指標併為它們製作動畫時,我們還需要包含元素。

鐘面

我們將從一個基本的時鐘設計開始,圓臉,簡單的小時,分鐘和秒針。

.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背景。我還新增了一個偽元素來向中心新增一個純黑色圓圈。然後可以根據需要將時鐘的指標放在該偽元素後面。

我們現在應該有這樣的結果。

時鐘——CSS 動畫

在新增指標之前,我們需要放置容器。

.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屬性設定為指標的底部,以便以後可以旋轉。

時鐘——CSS 動畫

分針

分針跟時針類似,但更長更細。

.minutes {
  background: #000;
  height: 40%;
  left: 49%;
  position: absolute;
  top: 10%;
  transform-origin: 50% 100%;
  width: 2%;
}
複製程式碼

時鐘——CSS 動畫

秒針

秒針再次變細,但也進一步向下設定,使其比中心延伸得更遠。為此,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;
}
複製程式碼

時鐘——CSS 動畫

動畫

停止的時鐘每天只能正確兩次。讓我們新增一些動畫來讓時鐘表現得更像真實的東西。

有些時鐘會隨著每秒跳躍,通常會產生滴答聲。有些時鐘會隨著手的平穩移動而發出嗚嗚聲。我們兩個都試試。首先,我們會讓雙手平穩移動。

我們可以使用一個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秒)旋轉一次。分針每小時旋轉一次,秒針每分鐘旋轉一次。

把它放在一起,我們現在有運動!

時鐘——CSS 動畫

如果你的眼睛非常敏銳,你甚至可以讓分針移動。它需要一個小時才能完成一個旋轉,十二個小時的時間來完成它的迴圈。

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

新增停頓

通過讓秒針在60個單獨的動作中全天候移動,我們可以讓指標更像普通時鐘。實現此目的的一種簡單方法是使用steps計時功能。然後每隻指標的animation屬性變為:

.minutes-container {
  animation: rotate 3600s infinite steps(60);
}
.seconds-container {
  animation: rotate 60s infinite steps(60);
}
複製程式碼

分針和秒針現在分六步走動。瀏覽器會自動計算這60個步驟中的每個步驟移動的距離。

時鐘——CSS 動畫

正確的時間

一切都很好,時間看起來不錯,但準確度如何呢?使用一點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屬性。

然後,將時鐘設定為當前系統時間。

時鐘——CSS 動畫

對齊秒針和分針

時鐘——CSS 動畫

當首次在螢幕上繪製時鐘時,在分針需要移動之前不到一分鐘。為了實現這一點,我們可以計算出第一分鐘結束的時間並手動輕推分針。由於我們使用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定時函式。這個計時功能讓秒針有些反彈。

時鐘——CSS 動畫

iOS7 風格

我非常喜歡Apple iOS 7中使用的時鐘的簡單性。他們已經伸長了指標,但我更喜歡較短的版本。

通過設計針部樣式並新增帶有數字的背景影像,我們可以輕鬆建立此外觀。

時鐘——CSS 動畫

這種設計本身就是Hans Hilfiker對瑞士鐵路時鐘的演變。通過改變一些樣式並新增新的背景影像,我們可以使我們的時鐘適應這種風格。

如果您想出其他設計,請告訴我。

使用 Moment.js

我計劃這篇文章的第一個想法之一是重建酒店鐘錶場景,三個時鐘顯示不同的時區。

調整不同時區的最簡單方法是使用令人驚歎的Moment.js 時區庫

時鐘——CSS 動畫

您可以在此Codepen上檢視程式碼。

瀏覽器相容性

現代瀏覽器可以處理所涉及的CSS過渡和動畫。 IE10 +,最近的Chrome和Firefox支援它們沒有字首,Safari需要-webkit字首。

不要忘記在JavaScript中使用字首屬性。

(完)

本文作者 Thinker

本文如有錯誤之處,請留言,我會及時更正

覺得對您有幫助的話就點個贊收藏吧!

歡迎轉載或分享,轉載時請註明出處

閱讀原文

相關文章