通过HTML, CSS, SVG 背景图 和 JavaScript实现一个钟表动画,效果如下:

See the Pen mac clock by Elaine (@ElaineXu) on CodePen.

一、搭建静态表盘

HTML结构

<div class="clock-bg">
    <span id="wu"></span>
    <div class="clock">
        <div class="hours-con"> 
            <div class="hours"></div>
        </div>
        <div class="minutes-con">
            <div class="minutes"></div>
        </div>
        <div class="seconds-con">
            <div class="seconds"></div>
        </div>
    </div>
    <span class="address">上海</span>
</div>

CSS样式

/*表盘*/
    .clock-bg{
      width: 150px;
      height: 150px;
      border-radius:10px;
      background-image:linear-gradient(to bottom, #484848 0%,#393939 25%, #494949 50%,#494949 50%,#040404 50%,#0d0d0d 75%,#11110f 100%);
      border:2px solid #010101;
      display: flex;
      align-items:center;
      justify-content:center;
      flex-direction:column;
    }
    .clock{
      width:100px;
      height:100px;
      background: #fff  url(https://cssanimation.rocks/images/posts/clocks/ios_clock.svg)  no-repeat center center; 
      margin:6px 0;
      position: relative;
      border-radius: 50%;
      background-size: 80%;
      box-shadow:0 0 2px rgba(67,67,67,0.3);
    }
    .address{
      color:#fff;
      text-shadow:0 0 1px rgba(0,0,0,0.2);
    }
        #wu{
      color:#101010;
      text-shadow:0 0 1px rgba(255,255,255,0.2);
    }

    .clock::after{
        width:6px;
        height:6px;
        border-radius:50%;
        position: absolute;
        top:50%;
        left:50%;
        z-index: 10;
        transform:translate(-50%,-50%);
        background:#e43c39;
        border:2px solid #fff;
        box-shadow:0 0  0 1px #454449;
        content:"";
        display: block;
    }
    .hours-con,.minutes-con,.seconds-con{
        position: absolute;
        left: 0;
        top: 0;
        right:0;
        bottom:0; 
    }
    /*时针*/
    .hours{
         position:absolute;  
         border-left:4px solid transparent;
         border-right:4px solid transparent;
         border-bottom:30px solid #000;
         top:22%;
         left:50%;
         margin-left:-4px;  
         transform-origin: 50% 100%;
    } 
    /*分针*/
    .minutes{
         position:absolute;
         border-left:4px solid transparent;
         border-right:4px solid transparent;
         border-bottom:40px solid #000; 
         top:10%;
         left:50%;
         margin-left:-4px; 
         transform-origin: 50% 100%; 
    }
    /*秒针*/
    .seconds-con{
      z-index:12; 
    }
    .seconds{
        position:absolute;
         width:2px;
         height:48%;
         top:2%;
         left:50%;  
         background:#e43c39;
         transform-origin: 50%  100%;
    }

js初始化静态刻度

window.onload=function(){
    init();
    function init(){
        initLocalClocks(); 
    }
 
    //初始化表盘刻度
    function initLocalClocks() {
        var date=new Date; 
        var hour=date.getHours();
        var min=date.getMinutes();
        var sec=date.getSeconds();
        var hands=[
        {
            hand:'hours',
            angle:hour*30+min/2
        },
        {
            hand:'minutes',
            angle:min*6
        },
        {
            hand:'seconds',
            angle:sec*6
        }
        ] 
        for(var i=0;i<hands.length;i++){ 
            var elements=document.querySelectorAll("."+hands[i].hand);  

            for(var j=0;j<elements.length;j++){
                elements[j].style.transform='rotate(+'+hands[i].angle+'deg)';
                elements[j].style.WebkitTransform='rotate('+hands[i].angle+'deg)';  
            }
        } 
   }
}

初始化刻度的静态表盘

二、添加动画

.hours-con{
    animation: rotate 43200s infinite linear;
}
.minutes-con{
  animation: rotate 3600s infinite steps(60);
}
.seconds-con{
    animation: rotate 60s infinite steps(60);
}
@keyframes rotate{
    to{
        transform:rotate(360deg);
    }
}

此时时钟基本已可正常转动,但是分针总是在秒针还没有转到12点刻度时已转到整刻度,误差如下图展示:

css实现动画的秒针和分针的误差

优化:

一、修改时针和分针的animation动画为transition动画

.minutes-con{
  transition: transform 0.3s cubic-bezier(.4,2.08,.55,.44);
}
.seconds-con{
  transition: transform 0.2s cubic-bezier(.4,2.08,.55,.44);
}

二、js设置秒针和分针转动

//设置秒针
function moveSecondHands(){
    var secCons=document.querySelectorAll(".seconds-con"); 
    setInterval(function(){
        for(var i=0;i<secCons.length;i++){
            if(secCons[i].angle===undefined){
                secCons[i].angle=6;
            }else{
                secCons[i].angle+=6;
            }
            secCons[i].style.transform="rotate("+secCons[i].angle+"deg)";
            secCons[i].style.webkitTransform="rotate("+secCons[i].angle+"deg)";
        } 
    },1000)
}
//设置分针
function moveMinuteHands(containers){  
    //先把分针转到延迟后的正时刻
    for(var i=0;i<containers.length;i++){
         containers[i].style.webkitTransform = 'rotateZ(6deg)';
        containers[i].style.transform = 'rotateZ(6deg)';
    }
    //分针进行正常的转动
    setInterval(function(){
        for(var i=0;i<containers.length;i++){ 
            containers[i].angle+=6; 
            containers[i].style.transform="rotate("+containers[i].angle+"deg)";
            containers[i].style.webkitTransform="rotate("+containers[i].angle+"deg)";
        } 
    },60000)
}
//延迟分针
function setUpMinuteHands(){
    var minCons=document.querySelectorAll(".minutes-con"); 
    var angle=minCons[0].getAttribute('data-second-angle');
    var delay=(360-angle)/6*1000;
    if(angle>0){
        setTimeout(function(){
             moveMinuteHands(minCons);
        },delay)
    }  
} 

三、将时针分针的转动js函数添加到初始化函数中

function init(){
    initLocalClocks();
    setUpMinuteHands();
    moveSecondHands();
}

译文出处 https://cssanimation.rocks/clocks

本文作者:徐小宁 转载请注明来自:携程设计委员会