Исходник Animated Button HTML/CSS/JS

(ノ◕ヮ◕)ノ*:・゚✧
Забаненный
Статус
Оффлайн
Регистрация
10 Ноя 2019
Сообщения
1,173
Реакции[?]
561
Поинты[?]
1K
Обратите внимание, пользователь заблокирован на форуме. Не рекомендуется проводить сделки.
Код:
<button id="button" class="ready" onclick="clickButton();">
 
  <div class="message submitMessage">
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 13 12.2">
      <polyline stroke="currentColor" points="2,7.1 6.5,11.1 11,7.1 "/>
      <line stroke="currentColor" x1="6.5" y1="1.2" x2="6.5" y2="10.3"/>
    </svg> <span class="button-text">Скачать</span>
  </div>
 
  <div class="message loadingMessage">
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 19 17">
      <circle class="loadingCircle" cx="2.2" cy="10" r="1.6"/>
      <circle class="loadingCircle" cx="9.5" cy="10" r="1.6"/>
      <circle class="loadingCircle" cx="16.8" cy="10" r="1.6"/>
    </svg>
  </div>
 
  <div class="message successMessage">
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 13 11">
      <polyline stroke="currentColor" points="1.4,5.8 5.1,9.5 11.6,2.1 "/>
    </svg> <span class="button-text">Удачно</span>
  </div>
</button>

<canvas id="canvas"></canvas>
Код:
@keyframes loading {
  0% {
    cy: 10;
  }
  25% {
    cy: 3;
  }
  50% {
    cy: 10;
  }
}
body {
  -webkit-font-smoothing: antialiased;
  background-color: #f4f7ff;
}

canvas {
  height: 100vh;
  pointer-events: none;
  position: fixed;
  width: 100%;
  z-index: 2;
}

button {
  background: none;
  border: none;
  color: #f4f7ff;
  cursor: pointer;
  font-family: 'Roboto', Arial;
  font-size: 14px;
  font-weight: 500;
  height: 40px;
  left: 50%;
  outline: none;
  overflow: hidden;
  padding: 0 10px;
  position: fixed;
  top: 50%;
  transform: translate(-50%, -50%);
  width: 190px;
  z-index: 1;
}
button::before {
  background: #1f2335;
  border-radius: 50px;
  box-shadow: 0 2px 5px rgba(0, 0, 0, 0.4) inset;
  content: '';
  display: block;
  height: 100%;
  margin: 0 auto;
  position: relative;
  transition: width 0.2s cubic-bezier(0.39, 1.86, 0.64, 1) 0.3s;
  width: 100%;
}

button.ready .submitMessage svg {
  opacity: 1;
  top: 1px;
  transition: top .4s ease 600ms, opacity .3s linear 600ms;
}
button.ready .submitMessage .button-text span {
  top: 0;
  opacity: 1;
  transition: all 0.2s ease calc(var(--dr) + 600ms);
}

button.loading::before {
  transition: width .3s ease;
  width: 80%;
}
button.loading .loadingMessage {
  opacity: 1;
}
button.loading .loadingCircle {
  animation-duration: 1s;
  animation-iteration-count: infinite;
  animation-name: loading;
  cy: 10;
}

button.complete .submitMessage svg {
  top: -30px;
  transition: none;
}
button.complete .submitMessage .button-text span {
  top: -8px;
  transition: none;
}
button.complete .loadingMessage {
  top: 80px;
}
button.complete .successMessage .button-text span {
  left: 0;
  opacity: 1;
  transition: all 0.2s ease calc(var(--d) + 1000ms);
}
button.complete .successMessage svg {
  stroke-dashoffset: 0;
  transition: stroke-dashoffset .3s ease-in-out 1.4s;
}

.button-text span {
  opacity: 0;
  position: relative;
}

.message {
  left: 50%;
  position: absolute;
  top: 50%;
  transform: translate(-50%, -50%);
  width: 100%;
}

.message svg {
  display: inline-block;
  fill: none;
  margin-right: 5px;
  stroke-linecap: round;
  stroke-linejoin: round;
  stroke-width: 2;
}

.submitMessage .button-text span {
  top: 8px;
  transition: all 0.2s ease var(--d);
}
.submitMessage svg {
  color: #5c86ff;
  margin-left: -1px;
  opacity: 0;
  position: relative;
  top: 30px;
  transition: top .4s ease, opacity .3s linear;
  width: 14px;
}

.loadingMessage {
  opacity: 0;
  transition: opacity 0.3s linear 0.3s, top 0.4s cubic-bezier(0.22, 0, 0.41, -0.57);
}
.loadingMessage svg {
  fill: #5c86ff;
  margin: 0;
  width: 22px;
}

.successMessage .button-text span {
  left: 5px;
  transition: all 0.2s ease var(--dr);
}
.successMessage svg {
  color: #5cffa1;
  stroke-dasharray: 20;
  stroke-dashoffset: 20;
  transition: stroke-dashoffset .3s ease-in-out;
  width: 14px;
}

.loadingCircle:nth-child(2) {
  animation-delay: 0.1s;
}

.loadingCircle:nth-child(3) {
  animation-delay: 0.2s;
}
Код:
const button = document.getElementById('button');
        var disabled = false;
        const canvas = document.getElementById('canvas');
        const ctx = canvas.getContext('2d');
        canvas.width = window.innerWidth;
        canvas.height = window.innerHeight;
        let cx = ctx.canvas.width / 2;
        let cy = ctx.canvas.height / 2;

        // add Confetti/Sequince objects to arrays to draw them
        let confetti = [];
        let sequins = [];

        // ammount to add on each button press
        const confettiCount = 20;
        const sequinCount = 10;

        // "physics" variables
        const gravityConfetti = 0.3;
        const gravitySequins = 0.55;
        const dragConfetti = 0.075;
        const dragSequins = 0.02;
        const terminalVelocity = 3;

        // colors, back side is darker for confetti flipping
        const colors = [
          { front : '#7b5cff', back: '#6245e0' }, // Purple
          { front : '#b3c7ff', back: '#8fa5e5' }, // Light Blue
          { front : '#5c86ff', back: '#345dd1' }  // Darker Blue
        ];

        // helper function to pick a random number within a range
        randomRange = (min, max) => Math.random() * (max - min) + min;

        // helper function to get initial velocities for confetti
        // this weighted spread helps the confetti look more realistic
        initConfettoVelocity = (xRange, yRange) => {
          const x = randomRange(xRange[0], xRange[1]);
          const range = yRange[1] - yRange[0] + 1;
          let y = yRange[1] - Math.abs(randomRange(0, range) + randomRange(0, range) - range);
          if (y >= yRange[1] - 1) {
            // Occasional confetto goes higher than the max
            y += (Math.random() < .25) ? randomRange(1, 3) : 0;
          }
          return {x: x, y: -y};
        }

        // Confetto Class
        function Confetto() {
          this.randomModifier = randomRange(0, 99);
          this.color = colors[Math.floor(randomRange(0, colors.length))];
          this.dimensions = {
            x: randomRange(5, 9),
            y: randomRange(8, 15),
          };
          this.position = {
            x: randomRange(canvas.width/2 - button.offsetWidth/4, canvas.width/2 + button.offsetWidth/4),
            y: randomRange(canvas.height/2 + button.offsetHeight/2 + 8, canvas.height/2 + (1.5 * button.offsetHeight) - 8),
          };
          this.rotation = randomRange(0, 2 * Math.PI);
          this.scale = {
            x: 1,
            y: 1,
          };
          this.velocity = initConfettoVelocity([-9, 9], [6, 11]);
        }
        Confetto.prototype.update = function() {
          // apply forces to velocity
          this.velocity.x -= this.velocity.x * dragConfetti;
          this.velocity.y = Math.min(this.velocity.y + gravityConfetti, terminalVelocity);
          this.velocity.x += Math.random() > 0.5 ? Math.random() : -Math.random();
          
          // set position
          this.position.x += this.velocity.x;
          this.position.y += this.velocity.y;

          // spin confetto by scaling y and set the color, .09 just slows cosine frequency
          this.scale.y = Math.cos((this.position.y + this.randomModifier) * 0.09);   
        }

        // Sequin Class
        function Sequin() {
          this.color = colors[Math.floor(randomRange(0, colors.length))].back,
          this.radius = randomRange(1, 2),
          this.position = {
            x: randomRange(canvas.width/2 - button.offsetWidth/3, canvas.width/2 + button.offsetWidth/3),
            y: randomRange(canvas.height/2 + button.offsetHeight/2 + 8, canvas.height/2 + (1.5 * button.offsetHeight) - 8),
          },
          this.velocity = {
            x: randomRange(-6, 6),
            y: randomRange(-8, -12)
          }
        }
        Sequin.prototype.update = function() {
          // apply forces to velocity
          this.velocity.x -= this.velocity.x * dragSequins;
          this.velocity.y = this.velocity.y + gravitySequins;
          
          // set position
          this.position.x += this.velocity.x;
          this.position.y += this.velocity.y;
        }

        // add elements to arrays to be drawn
        initBurst = () => {
          for (let i = 0; i < confettiCount; i++) {
            confetti.push(new Confetto());
          }
          for (let i = 0; i < sequinCount; i++) {
            sequins.push(new Sequin());
          }
        }

        // draws the elements on the canvas
        render = () => {
          ctx.clearRect(0, 0, canvas.width, canvas.height);
          
          confetti.forEach((confetto, index) => {
            let width = (confetto.dimensions.x * confetto.scale.x);
            let height = (confetto.dimensions.y * confetto.scale.y);
            
            // move canvas to position and rotate
            ctx.translate(confetto.position.x, confetto.position.y);
            ctx.rotate(confetto.rotation);

            // update confetto "physics" values
            confetto.update();
            
            // get front or back fill color
            ctx.fillStyle = confetto.scale.y > 0 ? confetto.color.front : confetto.color.back;
            
            // draw confetto
            ctx.fillRect(-width / 2, -height / 2, width, height);
            
            // reset transform matrix
            ctx.setTransform(1, 0, 0, 1, 0, 0);

            // clear rectangle where button cuts off
            if (confetto.velocity.y < 0) {
              ctx.clearRect(canvas.width/2 - button.offsetWidth/2, canvas.height/2 + button.offsetHeight/2, button.offsetWidth, button.offsetHeight);
            }
          })

          sequins.forEach((sequin, index) => { 
            // move canvas to position
            ctx.translate(sequin.position.x, sequin.position.y);
            
            // update sequin "physics" values
            sequin.update();
            
            // set the color
            ctx.fillStyle = sequin.color;
            
            // draw sequin
            ctx.beginPath();
            ctx.arc(0, 0, sequin.radius, 0, 2 * Math.PI);
            ctx.fill();

            // reset transform matrix
            ctx.setTransform(1, 0, 0, 1, 0, 0);

            // clear rectangle where button cuts off
            if (sequin.velocity.y < 0) {
              ctx.clearRect(canvas.width/2 - button.offsetWidth/2, canvas.height/2 + button.offsetHeight/2, button.offsetWidth, button.offsetHeight);
            }
          })

          // remove confetti and sequins that fall off the screen
          // must be done in seperate loops to avoid noticeable flickering
          confetti.forEach((confetto, index) => {
            if (confetto.position.y >= canvas.height) confetti.splice(index, 1);
          });
          sequins.forEach((sequin, index) => {
            if (sequin.position.y >= canvas.height) sequins.splice(index, 1);
          });

          window.requestAnimationFrame(render);
        }

        // cycle through button states when clicked
        clickButton = () => {
          if (!disabled) {
            disabled = true;
            // Loading stage
            button.classList.add('loading');
            button.classList.remove('ready');
            setTimeout(() => {
              // Completed stage
              button.classList.add('complete');
              button.classList.remove('loading');
              setTimeout(() => {
                window.initBurst();
                setTimeout(() => {
                  // Reset button so user can select it again
                  disabled = false;
                  button.classList.add('ready');
                  button.classList.remove('complete');
                }, 4000);
              }, 320);
            }, 1800);
          }
        }

        // re-init canvas if the window size changes
        resizeCanvas = () => {
          canvas.width = window.innerWidth;
          canvas.height = window.innerHeight;
          cx = ctx.canvas.width / 2;
          cy = ctx.canvas.height / 2;
        }

        // resize listenter
        window.addEventListener('resize', () => {
          resizeCanvas();
        });

        // click button on spacebar or return keypress
        document.body.onkeyup = (e) => {
          if (e.keyCode == 13 || e.keyCode == 32) {
            clickButton();
          }
        }

        // Set up button text transition timings on page load
        textElements = button.querySelectorAll('.button-text');
        textElements.forEach((element) => {
          characters = element.innerText.split('');
          let characterHTML = '';
          characters.forEach((letter, index) => {
            characterHTML += `<span class="char${index}" style="--d:${index * 30}ms; --dr:${(characters.length - index - 1) * 30}ms;">${letter}</span>`;
          })
          element.innerHTML = characterHTML;
        })

        // kick off the render loop
        render();
SS:
Пожалуйста, авторизуйтесь для просмотра ссылки.
 
Забаненный
Статус
Оффлайн
Регистрация
26 Мар 2021
Сообщения
19
Реакции[?]
26
Поинты[?]
0
Обратите внимание, пользователь заблокирован на форуме. Не рекомендуется проводить сделки.
Добрый вечер, Scare !
Прошу Вас, указывайте ссылки на первоисточник. Все темы с исходниками, которыми вы делитесь на данном форуме, просмотренные мной, не имеют ссылки. Уважайте чужой труд. Спасибо.

Пожалуйста, авторизуйтесь для просмотра ссылки.
 
BOOMER
Забаненный
Статус
Оффлайн
Регистрация
13 Фев 2021
Сообщения
110
Реакции[?]
18
Поинты[?]
0
Обратите внимание, пользователь заблокирован на форуме. Не рекомендуется проводить сделки.
Паста , хоть бы ссылку на создателя оставил
 
Начинающий
Статус
Оффлайн
Регистрация
21 Май 2021
Сообщения
12
Реакции[?]
1
Поинты[?]
0
Есть библа antd, у которой есть доп библа с анимациями, там можно всякие кастомные штуки делать такие
 
Сверху Снизу