CSS3动画实现3D倒计时效果

先介绍CSS3动画如何使用?两步即可搞定。

  1. 定义动画规则

    @keyframe animationName{  
         timeStamp{  
             attr1:value1;  
             attr2:value2;  
             ...
             attrn,valuen;  
         }  
     }
    复制代码

说明:

  • animationName表示动画名称;
  • timeStamp表示时间点,可取值from,to或0-100%,from表示0,to表示100%;
  • 每个时间点可以指定多个样式属性attr与对应值value。
  1. 元素应用动画

     elemSelector{  
         animation: animationName animationDuration;   
     }
    复制代码

说明:

  • elemSelector表示元素选择器
  • 执行一个动画至少指定动画名称animationName和动画时长animationDuration
  • animation属性是以下属性的简写形式,每个属性的含义说明如下表,
属性名称含义
animation-name@keyframe动画的名称
animation-duration动画的时长,需指定单位如s或ms,默认值为0
animation-timing-function动画的速度曲线,默认值为ease,其他取值有ease-in、ease-out、ease-in-out、linear、step-start、step-end、贝塞尔曲线函数cubic-bezier、步进函数steps
animation-delay动画延时多久开始,需指定指定单位如s或ms,默认为0,,取正值表示延时,负值表示超前
animation-iteration-count动画播放次数,默认为1
animation-direction动画是否在下一周期逆向播放,默认是normal,其他取值有reverse、alternate、alternate-reverse
animation-play-state动画的播放状态,是运行还是暂停,默认是running,其他取值有paused
animation-fill-mode动画执行前、后是否应用目标状态,默认是none,其他取值有forwards、backwards、both

重点来了,一个倒计时效果是如何实现的,先看效果。由于是压缩生成的gif,所以看起来会很快。

下面对主要代码进行说明,

  • HTML部分

      <!--用于呈现数字-->
      <div id="number"></div>
      <!--用于重新倒计时-->
      <button class="button">再来一次</button>
       <!--用于最后的声音播放。-->
      <audio ></audio>
    复制代码
  • CSS部分

      /*初始化数字div样式*/
      #number {
          position: absolute;
          top: 50%;
          left: 50%;
      
          text-align: center;
      
          -webkit-transform: translate3d(-50%, -50%, 0);
          -moz-transform: translate3d(-50%, -50%, 0);
          transform: translate3d(-50%, -50%, 0);
      }
      
      /*绑定动画*/
      .number-anim {
          -webkit-animation: animation_in 10s linear;
          -moz-animation: animation_in 10s linear;
          /*动画时长是10s,且动画的速度是线性的*/
          animation: animation_in 10s linear;
      }
      
      /*定义动画规则*/
      @keyframes animation_in {
          0 {}
          10% {
              /*由于动画时长是10s,此时是1s时刻,字体大小变为100px,z方向距离主屏幕为300px*/
              font-size: 100px;
              -webkit-transform: translate3d(-50%, -50%, -300px);
              -moz-transform: translate3d(-50%, -50%, -300px);
              transform: translate3d(-50%, -50%, -300px);
          }
          11% {
              /*随后字体大小变为300px,z方向距离主屏幕为0,后面每到整秒数都会重复进行*/
              font-size: 300px;
              -webkit-transform: translate3d(-50%, -50%, 0);
              -moz-transform: translate3d(-50%, -50%, 0);
              transform: translate3d(-50%, -50%, 0);
          }
          20% {
              font-size: 100px;
              -webkit-transform: translate3d(-50%, -50%, -300px);
              -moz-transform: translate3d(-50%, -50%, -300px);
              transform: translate3d(-50%, -50%, -300px);
          }
          21% {
              font-size: 300px;
              -webkit-transform: translate3d(-50%, -50%, 0);
              -moz-transform: translate3d(-50%, -50%, 0);
              transform: translate3d(-50%, -50%, 0);
          }
          30% {
              font-size: 100px;
              -webkit-transform: translate3d(-50%, -50%, -300px);
              -moz-transform: translate3d(-50%, -50%, -300px);
              transform: translate3d(-50%, -50%, -300px);
          }
          31% {
              font-size: 300px;
              -webkit-transform: translate3d(-50%, -50%, 0);
              -moz-transform: translate3d(-50%, -50%, 0);
              transform: translate3d(-50%, -50%, 0);
          }
          40% {
              font-size: 100px;
              -webkit-transform: translate3d(-50%, -50%, -300px);
              -moz-transform: translate3d(-50%, -50%, -300px);
              transform: translate3d(-50%, -50%, -300px);
          }
          41% {
              font-size: 300px;
              -webkit-transform: translate3d(-50%, -50%, 0);
              -moz-transform: translate3d(-50%, -50%, 0);
              transform: translate3d(-50%, -50%, 0);
          }
          50% {
              font-size: 100px;
              -webkit-transform: translate3d(-50%, -50%, -300px);
              -moz-transform: translate3d(-50%, -50%, -300px);
              transform: translate3d(-50%, -50%, -300px);
          }
          51% {
              font-size: 300px;
              -webkit-transform: translate3d(-50%, -50%, 0);
              -moz-transform: translate3d(-50%, -50%, 0);
              transform: translate3d(-50%, -50%, 0);
          }
          60% {
              font-size: 100px;
              -webkit-transform: translate3d(-50%, -50%, -300px);
              -moz-transform: translate3d(-50%, -50%, -300px);
              transform: translate3d(-50%, -50%, -300px);
          }
          61% {
              font-size: 300px;
              -webkit-transform: translate3d(-50%, -50%, 0);
              -moz-transform: translate3d(-50%, -50%, 0);
              transform: translate3d(-50%, -50%, 0);
          }
          70% {
              font-size: 100px;
              -webkit-transform: translate3d(-50%, -50%, -300px);
              -moz-transform: translate3d(-50%, -50%, -300px);
              transform: translate3d(-50%, -50%, -300px);
          }
          71% {
              font-size: 300px;
              -webkit-transform: translate3d(-50%, -50%, 0);
              -moz-transform: translate3d(-50%, -50%, 0);
              transform: translate3d(-50%, -50%, 0);
          }
          80% {
              font-size: 100px;
              -webkit-transform: translate3d(-50%, -50%, -300px);
              -moz-transform: translate3d(-50%, -50%, -300px);
              transform: translate3d(-50%, -50%, -300px);
          }
          81% {
              font-size: 300px;
              -webkit-transform: translate3d(-50%, -50%, 0);
              -moz-transform: translate3d(-50%, -50%, 0);
              transform: translate3d(-50%, -50%, 0);
          }
          90% {
              font-size: 100px;
              -webkit-transform: translate3d(-50%, -50%, -300px);
              -moz-transform: translate3d(-50%, -50%, -300px);
              transform: translate3d(-50%, -50%, -300px);
          }
          91% {
              font-size: 300px;
              -webkit-transform: translate3d(-50%, -50%, 0);
              -moz-transform: translate3d(-50%, -50%, 0);
              transform: translate3d(-50%, -50%, 0);
          }
          100% {
              font-size: 100px;
              -webkit-transform: translate3d(-50%, -50%, -300px);
              -moz-transform: translate3d(-50%, -50%, -300px);
              transform: translate3d(-50%, -50%, -300px);
          }
       }
    复制代码
  • JS部分

    window.onload = function() {
      
      //第一步:定义全局变量
      num = 10;//数字内容
      isCounting = true;//是否正在计数
      timer = null;//定时器
      numberDiv = document.querySelector("#number");
      audio = document.querySelector("audio");
      button = document.querySelector(".button");
    
      //第二步:初始化
      init();
    
      //第三步:开始倒计时
      timer = setInterval(count, 1000);
        
    }
    复制代码

    初始化函数声明如下,

       function init() {
          numberDiv.innerHTML = num;
          numberDiv.style.color =  getRandomColor();
          numberDiv.style.fontSize = "300px";
          numberDiv.className = "number-anim";
        
          button.addEventListener("click", function() {
              if (isCounting) {
                  return;
              }
              isCounting = true;
              num = 10;
      
              numberDiv.innerHTML = num;
              numberDiv.style.color = getRandomColor();   
              numberDiv.style.fontSize = "300px";
              
              //先解绑,再使用setTimeout使浏览器重新渲染页面,重新绑定
              //setTimeout只是一种方式,只要能使浏览器重新渲染即可      
              numberDiv.className = null;
              setTimeout(function() {
                  numberDiv.className = "number-anim";
      
                  timer = setInterval(count, 1000);
              }, 30); 
          }, false);
      }
    复制代码

    倒计数函数声明如下,

      function count() {
      
          numberDiv.innerHTML = --num;
          numberDiv.style.color = getRandomColor();
        
          if (num == 0) {
              clearInterval(timer);
      
              audio.src="./audio/readygo.mp3";
              audio.play();
      
              numberDiv.innerHTML = "Ready Go!";
              numberDiv.style.color = getRandomColor();
              numberDiv.style.fontSize = "100px";
      
              numberDiv.style.opacity = 0.8;
              numberDiv.style.filter = "alpha(opacity=80)";
              CompatibleFunc(numberDiv, "Transition", "opacity 1s");
      
              isCounting = false;
          }
      }
    复制代码

这里有一个地方需要特别注意,避免以后踩坑。

关于动画样式的解绑与绑定。

动画样式animation一执行结束,就不再起作用了,要使其重新生效,需要重新绑定。我试了4种方式。

  • 第一种是直接解绑,然后再绑定。

      numberDiv.className = null;
      numberDiv.className = "number-anim";
    复制代码

    结果是不能使动画重新生效。

  • 第二种是使用classlist属性进行解绑定。

      numberDiv.classList.toggle("number-anim");
      numberDiv.classList.toggle("number-anim");
    复制代码

    classList返回类名列表对象,调用toggle方法,若类名存在则删除,返回false,若类名不存在则添加,返回true,所以要调用两次,第一次删除类名,第二次添加类名。但是结果依然是不能使动画重新生效。

  • 第三种是开启定时器。

    先解绑,再利用定时器使浏览器重新渲染页面,重新绑定。setTimeout只是一种方式,只要能使浏览器重新渲染即可,最终动画重新生效。

      numberDiv.className = null;
      setTimeout(function() {
          numberDiv.className = "number-anim";
      }, 30); 
    复制代码

    在mozilla官方文档介绍了另一种重新渲染方式,

    https://developer.mozilla.org/zh-CN/docs/Web/CSS/CSS_Animations/Tips
    复制代码

    应用在这里的话,写法是,

      numberDiv.className = null;
      window.requestAnimationFrame(function(){
          window.requestAnimationFrame(function(){
              numberDiv.className = "number-anim";
          });
      });
    复制代码
  • 第四种是借助其他重新渲染途径,如颜色、内容、大小的变化。

      numberDiv.className = null;
    
      numberDiv.innerHTML = num;
      numberDiv.style.color = getRandomColor();   
      numberDiv.style.fontSize = "300px";
      
      numberDiv.className = "number-anim";
    复制代码

    结果IE和Microsoft Edge 浏览器是支持的,但是FireFox和Chrome不支持, 但这是不是也说明了Chrome和FireFox已经对浏览器渲染做了优化?

简而言之,要使动画重新生效,需要触发浏览器重新渲染。
好了,附上源码链接。

https://github.com/muzhidong/frontend-demo/tree/master/countdown
复制代码
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值