譯者注:本文內容爲 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
本文若有錯誤之處,請留言,我會及時更正
以爲對您有幫助的話就點個贊或收藏吧!
歡迎轉載或分享,轉載時請註明出處