下雪的2021新年倒计时主题特效

基于canvas制作全屏飘雪背景,2021年翻页倒计时间动画特效。适用于各种活动主题倒计时特效。两种特效结合可以自由拆分使用。
在这里插入图片描述

*,
*:before,
*:after {
  -webkit-box-sizing: border-box;
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

body {
  background: #73cdc0;
}

canvas#snow {
  width: 100vw;
  height: 100vh;
  position: absolute;
  pointer-events: none;
}

.container {
  width: 600px;
  text-align: center;
  position: absolute;
  -webkit-transform: translate(-50%, -50%);
  -ms-transform: translate(-50%, -50%);
  transform: translate(-50%, -50%);
  top: 50%;
  left: 50%;
  font-family: 'Mada', sans-serif;
}

.intro {
  margin: 5% auto;
  color: #e16f97;
  letter-spacing: 1px;
  word-spacing: 12px;
}

.intro span {
  font-size: 40px;
  font-family: 'Limelight', cursive;
}

.countdown-wrapper {
  display: -webkit-box;
  display: -ms-flexbox;
  display: flex;
  -ms-flex-pack: distribute;
  justify-content: space-around;
  margin: 5% auto;
  color: #fff;
}

label,
output,
.time-el span {
  display: block;
}

.time-el {
  position: relative;
}

.time-el:not(:last-child):after {
  content: ":";
  position: absolute;
  right: -30px;
  top: 28%;
  font-size: 30px;
  color: #e16f97;
}

.time-el .digit {
  position: relative;
  width: 100px;
  height: 90px;
  display: inline-block;
  font-size: 50px;
  line-height: 90px;
  font-family: 'Limelight', cursive;
}

.inner {
  height: 200%;
  width: 100%;
  position: absolute;
}

.time-el .top,
.time-el .bottom {
  position: absolute;
  height: 50%;
  width: 100%;
  overflow: hidden;
  left: 0;
  right: 0;
  margin: auto;
  -webkit-backface-visibility: hidden;
  backface-visibility: hidden;
}



.time-el .bottom {
  -webkit-transform-origin: 50% 0%;
  -ms-transform-origin: 50% 0%;
  transform-origin: 50% 0%;

}

.time-el label {
  font-size: 10px;
  letter-spacing: 1px;
  color: #e16f97;
}


.current .top {
  z-index: 3;
  -webkit-transform-origin: 50% 100%;
  -ms-transform-origin: 50% 100%;
  transform-origin: 50% 100%;
  -webkit-transform: perspective(150px);
  transform: perspective(150px);
  border-top-left-radius: 6px;
  border-top-right-radius: 6px;
  background: #036161;
  color: #dcdcd6;
}

.next .top {
  z-index: 4;
  -webkit-transform-origin: 50% 0;
  -ms-transform-origin: 50% 0;
  transform-origin: 50% 0;
  -webkit-transform: perspective(150px) rotateX(180deg);
  transform: perspective(150px) rotateX(180deg);
  bottom: 0;
  border-bottom-left-radius: 6px;
  border-bottom-right-radius: 6px;
  background: teal;
}

.next .top .inner {
  position: absolute;
  top: -100%;
  left: 0;
  right: 0;
  margin: auto;
}

.current .bottom {
  z-index: 1;
  top: 0;
  border-top-left-radius: 6px;
  border-top-right-radius: 6px;
  background: #036161;
  color: #dcdcd6;
}

.next .bottom {
  z-index: 2;
  bottom: 0;
  border-bottom-left-radius: 6px;
  border-bottom-right-radius: 6px;
  background: teal;
}

.next .bottom .inner {
  position: absolute;
  top: -100%;
  left: 0;
  right: 0;
  margin: auto;
}
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>新年倒计时</title>

<link type="text/css" href="css/style.css" rel="stylesheet" />

<script type="text/javascript" src="js/jquery.min.js"></script>

<script type="text/javascript" src="js/TweenMax.min.js"></script>

</head>
<body>
<div class="container">
  <h1 class="intro"><span>2021</span> IS COMING IN</h1>
  <div class="countdown-wrapper">
    <div class="days time-el">
      <output id="days">
        <div class="digit">
         <div class="next">
        <span class="top"><span class="inner"></span></span>
        <span class="bottom"><span class="inner"></span></span>
          </div>
         <div class="current">
        <span class="top"><span class="inner"></span></span>
        <span class="bottom"><span class="inner"></span></span>
          </div>
      </div>
      </output>
      <label for="days">天(S)</label>
    </div>
    <div class="hours time-el">
      <output id="hours">
       <div class="digit">
         <div class="next">
        <span class="top"><span class="inner"></span></span>
        <span class="bottom"><span class="inner"></span></span>
          </div>
         <div class="current">
        <span class="top"><span class="inner"></span></span>
        <span class="bottom"><span class="inner"></span></span>
          </div>
      </div>
      </output>
      <label for="hours">时(S)</label>
    </div>
    <div class="minutes time-el">
      <output id="minutes">
        <div class="digit">
         <div class="next">
        <span class="top"><span class="inner"></span></span>
        <span class="bottom"><span class="inner"></span></span>
          </div>
         <div class="current">
        <span class="top"><span class="inner"></span></span>
        <span class="bottom"><span class="inner"></span></span>
          </div>
      </div>
      </output>
      <label for="minutes">分(S)</label>
    </div>
    <div class="seconds time-el">
      <output id="seconds">
       <div class="digit">
         <div class="next">
        <span class="top"><span class="inner"></span></span>
        <span class="bottom"><span class="inner"></span></span>
          </div>
         <div class="current">
        <span class="top"><span class="inner"></span></span>
        <span class="bottom"><span class="inner"></span></span>
          </div>
      </div>
      </output>
      <label for="seconds">秒(S)</label>
    </div>
  </div>
</div>

<canvas id="snow"></canvas>

</body>
</html>
let targetTime = new Date("Jan 1, 2021");

let oneSecond = 1000;
let oneMinute = oneSecond * 60;
let oneHour = oneMinute * 60;
let oneDay = oneHour * 24;

let $daysEl = $(".time-el #days");
let $hoursEl = $(".time-el #hours");
let $minutesEl = $(".time-el #minutes");
let $secondsEl = $(".time-el #seconds");

function startCountDown() {
  updateTick();
  let timeInterval = setInterval(updateTick, oneSecond);
  function updateTick() {
    let timeLeft = Date.parse(targetTime) - Date.parse(new Date());
    // only allow flip if the value has changed
    if (+$daysEl.find('.next .top .inner').html() !== +Math.floor(timeLeft / oneDay)) flipMe($daysEl);
    if (+$hoursEl.find('.next .top .inner').html() !== +Math.floor(timeLeft % oneDay / oneHour)) flipMe($hoursEl);
    if (+$minutesEl.find('.next .top .inner').html() !== +Math.floor(timeLeft % oneHour / oneMinute)) flipMe($minutesEl);
    if (+$secondsEl.find('.next .top .inner').html() !== +Math.floor(timeLeft % oneMinute / oneSecond)) flipMe($secondsEl);
    // update values
    $daysEl.find('.next .top .inner, .current .bottom .inner').html(Math.floor(timeLeft / oneDay));
    $hoursEl.find('.next .top .inner, .current .bottom .inner').html(("0" + Math.floor(timeLeft % oneDay / oneHour)).slice(-2));
    $minutesEl.find('.next .top .inner, .current .bottom .inner').html(("0" + Math.floor(timeLeft % oneHour / oneMinute)).slice(-2));
    $secondsEl.find('.next .top .inner, .current .bottom .inner').html(("0" + Math.floor(timeLeft % oneMinute / oneSecond)).slice(-2));


    function flipMe(el) {
      let tl = new TimelineMax().
      to(el.find('.current .top'), 0.9, { rotationX: -180, ease: Power1.easeInOut, onComplete: function () {
          $daysEl.find('.current .top .inner, .next .bottom .inner').html(Math.floor(timeLeft / oneDay));
          $hoursEl.find('.current .top .inner, .next .bottom .inner').html(("0" + Math.floor(timeLeft % oneDay / oneHour)).slice(-2));
          $minutesEl.find('.current .top .inner, .next .bottom .inner').html(("0" + Math.floor(timeLeft % oneHour / oneMinute)).slice(-2));
          $secondsEl.find('.current .top .inner, .next .bottom .inner').html(("0" + Math.floor(timeLeft % oneMinute / oneSecond)).slice(-2));
          TweenMax.set(el.find('.current .top'), { rotationX: 0 });
        } }, 0).
      to(el.find('.next .top'), 0.9, { rotationX: 0, ease: Power1.easeInOut, clearProps: 'all' }, 0);
    }

    if (timeLeft <= 0) clearInterval(timeInterval);
  }
}


const LetItSnow = function () {
  let canvas;
  let ctx;
  let durationLimit_ms;

  const snowflakes = [];
  const count = 150;
  let paused = false;
  let complete = false;

  function update(time) {
    snowflakes.forEach(function (el) {
      el.update(time);
    });
  }

  function resize() {
    ctx.canvas.width = canvas.offsetWidth;
    ctx.canvas.height = canvas.offsetHeight;
    update();
  }

  function draw() {
    ctx.clearRect(0, 0, canvas.offsetWidth, canvas.offsetHeight);
    snowflakes.forEach(function (el) {
      el.draw();
    });
  }

  function loop(time) {
    // if (time >= durationLimit_ms) LetItSnow.paused = true;
    draw();
    update(time);
    if (!LetItSnow.complete) window.requestAnimationFrame(loop);
  }

  function addSnowflakes() {
    for (var i = 0; i < count; i++) {
      snowflakes.push(SnowFlake(canvas));
    };
  }

  function events() {
    window.addEventListener('resize', resize);
  }

  function init(canvasEl, durationInSec) {
    // canvas = document.querySelector(`${canvasEl}`);
    canvas = document.querySelector(canvasEl);
    ctx = canvas.getContext('2d');
    durationLimit_ms = durationInSec * 1000;
    addSnowflakes();
    events();
    loop();
    resize();
  }

  return {
    init: init,
    paused: paused,
    complete: complete };


}();

function SnowFlake(canvEl) {
  const canvas = canvEl;
  const ctx = canvas.getContext('2d');

  function random(min, max) {
    return min + Math.random() * (max - min);
  }

  var x = random(0, canvas.offsetWidth);
  var y = random(-canvas.offsetHeight, 0);
  var ff = random(0.5, 1);
  var fill = 'rgba(255, 255, 255, ' + ff + ')';
  const radius = random(0.25, 7.0);

  var i = 0;
  var easeDuration_ms = 5 * 60;


  var gravity = 2;
  var angle = random(-1, 1);
  var density = random(0, 1000);
  var speed = 0;
  var wind = 0;

  function draw() {
    ctx.beginPath();
    ctx.arc(x, y, radius, 0, 2 * Math.PI);
    ctx.fillStyle = fill;
    ctx.fill();
    ctx.closePath();
  }

  function animateSnowFall(time) {
    const hitGround = y > canvas.offsetHeight;
    angle += 0.02;

    if (hitGround) {
      y = 0;
      x = random(0, canvas.offsetWidth);
    } else {
      y += speed;
      x += wind;

      if (LetItSnow.paused) {
        slowDownAndPause(speed, wind);
      } else {
        // creating a curved movement and speed for diffrent snowflakes
        speed = 0.15 * (Math.cos(angle + density) + 1 + radius * 3);
        wind = 0.5 * (Math.sin(angle) * 2);
      }

    }
  }
  function slowDownAndPause() {
    if (i < easeDuration_ms) {
      // simulating easeOutSine
      speed = speed - speed * Math.sin(i / easeDuration_ms * (Math.PI / 2));
      wind = wind - wind * Math.sin(i / easeDuration_ms * (Math.PI / 2));
      i++;
    } else {
      LetItSnow.complete = true;
    }
  }

  function update(time) {
    animateSnowFall(time);
  }

  return {
    update: update,
    draw: draw,
    slowDownAndPause: slowDownAndPause };

}


$(function () {
  startCountDown();
  LetItSnow.init('#snow');
});
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值