Интерактивная кнопка скачивания файла CSS & JQuery

Красивая реализация эффекта для кнопки со скачиванием файла. При клике происходит анимация скачивания с процентом загрузки. По окончанию анимации всплывает сообщение о завершении скачивания.

Для удобства можно скачать готовый .zip-архив внизу статьи.

Содержание
  1. HTML
  2. CSS
  3. JS (JQuery)

HTML

<a class="dl-button" href="">
  <div>
    <div class="icon">
      <div>
        <svg class="arrow" viewBox="0 0 20 18" fill="currentColor">
          <polygon points="8 0 12 0 12 9 15 9 10 14 5 9 8 9"></polygon>
        </svg>
        <svg class="shape" viewBox="0 0 20 18" fill="currentColor">
          <path
            d="M4.82668561,0 L15.1733144,0 C16.0590479,0 16.8392841,0.582583769 17.0909106,1.43182334 L19.7391982,10.369794 C19.9108349,10.9490677 19.9490212,11.5596963 19.8508905,12.1558403 L19.1646343,16.3248465 C19.0055906,17.2910371 18.1703851,18 17.191192,18 L2.80880804,18 C1.82961488,18 0.994409401,17.2910371 0.835365676,16.3248465 L0.149109507,12.1558403 C0.0509788145,11.5596963 0.0891651114,10.9490677 0.260801785,10.369794 L2.90908938,1.43182334 C3.16071592,0.582583769 3.94095214,0 4.82668561,0 Z">
          </path>
        </svg>
      </div><span></span>
    </div>
    <div class="label">
      <div class="show default">Download</div>
      <div class="state">
        <div class="counter">
          <ul>
            <li></li>
            <li>1</li>
          </ul>
          <ul>
            <li>0</li>
            <li>1</li>
            <li>2</li>
            <li>3</li>
            <li>4</li>
            <li>5</li>
            <li>6</li>
            <li>7</li>
            <li>8</li>
            <li>9</li>
            <li>0</li>
          </ul>
          <ul>
            <li>0</li>
            <li>1</li>
            <li>2</li>
            <li>3</li>
            <li>4</li>
            <li>5</li>
            <li>6</li>
            <li>7</li>
            <li>8</li>
            <li>9</li>
            <li>0</li>
            <li>1</li>
            <li>2</li>
            <li>3</li>
            <li>4</li>
            <li>5</li>
            <li>6</li>
            <li>7</li>
            <li>8</li>
            <li>9</li>
            <li>0</li>
            <li>1</li>
            <li>2</li>
            <li>3</li>
            <li>4</li>
            <li>5</li>
            <li>6</li>
            <li>7</li>
            <li>8</li>
            <li>9</li>
            <li>0</li>
          </ul>
          <span>%</span>
        </div>
        <span>Done</span>
      </div>
    </div>
    <div class="progress"></div>
  </div>
</a>
<a class="restart" href="">
  <svg viewBox="0 0 16 16" fill="currentColor">
    <path
      d="M4.5,4.5c1.9-1.9,5.1-1.9,7,0c0.7,0.7,1.2,1.7,1.4,2.7l2-0.3C14.7,5.4,14,4.1,13,3.1c-2.7-2.7-7.1-2.7-9.9,0 L0.9,0.9L0.2,7.3l6.4-0.7L4.5,4.5z">
    </path>
    <path
      d="M15.8,8.7L9.4,9.4l2.1,2.1c-1.9,1.9-5.1,1.9-7,0c-0.7-0.7-1.2-1.7-1.4-2.7l-2,0.3 C1.3,10.6,2,11.9,3,12.9c1.4,1.4,3.1,2,4.9,2c1.8,0,3.6-0.7,4.9-2l2.2,2.2L15.8,8.7z">
    </path>
  </svg>
  Restart
</a>

CSS

.dl-button {
  --duration: 4000;
  --success: #16BF78;
  --grey-light: #99A3BA;
  --grey: #6C7486;
  --grey-dark: #3F4656;
  --light: #CDD9ED;
  --shadow: rgba(18, 22, 33, .6);
  --shadow-dark: rgba(18, 22, 33, .85);
  display: block;
  text-decoration: none;
  -webkit-perspective: 500px;
  perspective: 500px;
}

.dl-button>div {
  position: relative;
  background: #fff;
  border-radius: 5px;
  overflow: hidden;
  display: -webkit-box;
  display: flex;
  padding: 16px 24px;
  box-shadow: 0 4px 12px var(--shadow);
}

.dl-button>div .icon {
  --color: var(--grey);
  margin-right: 12px;
  position: relative;
  -webkit-transform: translateZ(8px);
  transform: translateZ(8px);
}

.dl-button>div .icon div {
  overflow: hidden;
  position: relative;
  width: 20px;
  height: 22px;
}

.dl-button>div .icon div:before,
.dl-button>div .icon div:after {
  content: '';
  position: absolute;
  width: 2px;
  height: 2px;
  top: 2px;
  -webkit-transition: opacity .3s ease;
  transition: opacity .3s ease;
}

.dl-button>div .icon div:before {
  left: 6px;
  background-image: radial-gradient(circle at 0 100%, var(--color) 2px, #fff 0px);
}

.dl-button>div .icon div:after {
  right: 6px;
  background-image: radial-gradient(circle at 100% 100%, var(--color) 2px, #fff 0px);
}

.dl-button>div .icon div svg {
  width: 20px;
  height: 18px;
  display: block;
  margin-top: 2px;
  position: relative;
  z-index: 1;
}

.dl-button>div .icon div svg.arrow {
  color: #fff;
  position: absolute;
  left: 0;
  top: 0;
  z-index: 2;
  -webkit-transform: translateY(-1px);
  transform: translateY(-1px);
}

.dl-button>div .icon div svg.shape {
  color: var(--color);
  -webkit-transition: color .4s ease;
  transition: color .4s ease;
}

.dl-button>div .icon span {
  --s: 1;
  position: absolute;
  left: 1px;
  right: 1px;
  bottom: 2px;
  background: var(--color);
  height: 6px;
  border-radius: 50%;
  display: block;
  -webkit-transform: translateY(0) scale(var(--s));
  transform: translateY(0) scale(var(--s));
}

.dl-button>div .label {
  --color: var(--grey-dark);
  line-height: 22px;
  font-size: 16px;
  font-weight: 500;
  color: var(--color);
  position: relative;
  -webkit-transition: color .4s ease;
  transition: color .4s ease;
  -webkit-transform: translateZ(8px);
  transform: translateZ(8px);
}

.dl-button>div .label>div {
  display: -webkit-box;
  display: flex;
  -webkit-transition: opacity .25s ease;
  transition: opacity .25s ease;
}

.dl-button>div .label>div:not(.show) {
  position: absolute;
  left: 0;
  top: 0;
  opacity: 0;
}

.dl-button>div .label>div.hide {
  opacity: 0;
}

.dl-button>div .label>div .counter {
  overflow: hidden;
  display: -webkit-box;
  display: flex;
  height: 18px;
  line-height: 18px;
  margin: 2px 0;
  position: relative;
  -webkit-transition: opacity .3s ease;
  transition: opacity .3s ease;
}

.dl-button>div .label>div .counter:before,
.dl-button>div .label>div .counter:after {
  content: '';
  display: block;
  position: absolute;
  left: 0;
  right: 0;
  height: 3px;
  z-index: 1;
}

.dl-button>div .label>div .counter:before {
  top: 0;
  background: -webkit-gradient(linear, left top, left bottom, from(white), to(rgba(255, 255, 255, 0)));
  background: linear-gradient(to bottom, white 0%, rgba(255, 255, 255, 0) 100%);
}

.dl-button>div .label>div .counter:after {
  bottom: 0;
  background: -webkit-gradient(linear, left bottom, left top, from(white), to(rgba(255, 255, 255, 0)));
  background: linear-gradient(to top, white 0%, rgba(255, 255, 255, 0) 100%);
}

.dl-button>div .label>div .counter span {
  display: inline-block;
  margin: 0 4px 0 2px;
}

.dl-button>div .label>div .counter ul {
  --y: 0;
  margin: 0;
  padding: 0;
  list-style: none;
  width: 10px;
  height: 18px;
  -webkit-backface-visibility: hidden;
  -webkit-transform: translateY(var(--y)) translateZ(0);
  transform: translateY(var(--y)) translateZ(0);
}

.dl-button>div .label>div .counter ul:nth-child(1) {
  -webkit-transition: -webkit-transform calc(var(--duration) * .2ms) ease-in-out;
  transition: -webkit-transform calc(var(--duration) * .2ms) ease-in-out;
  transition: transform calc(var(--duration) * .2ms) ease-in-out;
  transition: transform calc(var(--duration) * .2ms) ease-in-out, -webkit-transform calc(var(--duration) * .2ms) ease-in-out;
}

.dl-button>div .label>div .counter ul:nth-child(2) {
  -webkit-transition: -webkit-transform calc(var(--duration) * .8ms) ease-in-out;
  transition: -webkit-transform calc(var(--duration) * .8ms) ease-in-out;
  transition: transform calc(var(--duration) * .8ms) ease-in-out;
  transition: transform calc(var(--duration) * .8ms) ease-in-out, -webkit-transform calc(var(--duration) * .8ms) ease-in-out;
}

.dl-button>div .label>div .counter ul:nth-child(3) {
  -webkit-transition: -webkit-transform calc(var(--duration) * .8ms) ease-in-out;
  transition: -webkit-transform calc(var(--duration) * .8ms) ease-in-out;
  transition: transform calc(var(--duration) * .8ms) ease-in-out;
  transition: transform calc(var(--duration) * .8ms) ease-in-out, -webkit-transform calc(var(--duration) * .8ms) ease-in-out;
}

.dl-button>div .label>div .counter ul li {
  width: 10px;
  height: 18px;
}

.dl-button>div .label>div .counter.hide {
  opacity: 0;
}

.dl-button>div .progress {
  --s: 0;
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 3px;
  -webkit-transform-origin: 50% 100%;
  transform-origin: 50% 100%;
  -webkit-transform: scaleY(var(--s));
  transform: scaleY(var(--s));
  -webkit-transition: -webkit-transform .4s ease;
  transition: -webkit-transform .4s ease;
  transition: transform .4s ease;
  transition: transform .4s ease, -webkit-transform .4s ease;
}

.dl-button>div .progress:before,
.dl-button>div .progress:after {
  --s: 1;
  content: '';
  background: var(--success);
  position: absolute;
  left: 0;
  top: 0;
  bottom: 0;
  right: 0;
  -webkit-transform-origin: 0 50%;
  transform-origin: 0 50%;
  -webkit-transform: scaleX(var(--s));
  transform: scaleX(var(--s));
}

.dl-button>div .progress:before {
  opacity: .35;
}

.dl-button>div .progress:after {
  --s: 0;
  -webkit-transition: -webkit-transform calc(var(--duration) * .9ms) ease-in-out;
  transition: -webkit-transform calc(var(--duration) * .9ms) ease-in-out;
  transition: transform calc(var(--duration) * .9ms) ease-in-out;
  transition: transform calc(var(--duration) * .9ms) ease-in-out, -webkit-transform calc(var(--duration) * .9ms) ease-in-out;
}

.dl-button.active>div {
  -webkit-animation: button calc(var(--duration) * 1ms) linear forwards;
  animation: button calc(var(--duration) * 1ms) linear forwards;
}

.dl-button.active>div .icon div:before,
.dl-button.active>div .icon div:after {
  opacity: 0;
  -webkit-transition-delay: .4s;
  transition-delay: .4s;
}

.dl-button.active>div .icon svg.arrow {
  -webkit-animation: arrow calc(var(--duration) * .18ms) linear 4 calc(var(--duration) * .2ms);
  animation: arrow calc(var(--duration) * .18ms) linear 4 calc(var(--duration) * .2ms);
}

.dl-button.active>div .icon span {
  -webkit-animation: span calc(var(--duration) * .18ms) linear 4 calc(var(--duration) * .2ms);
  animation: span calc(var(--duration) * .18ms) linear 4 calc(var(--duration) * .2ms);
}

.dl-button.active>div .label>div .counter ul:nth-child(1) {
  --y: -18px;
  -webkit-transition-delay: calc(var(--duration) * .72ms);
  transition-delay: calc(var(--duration) * .72ms);
}

.dl-button.active>div .label>div .counter ul:nth-child(2) {
  --y: -180px;
  -webkit-transition-delay: calc(var(--duration) * .09ms);
  transition-delay: calc(var(--duration) * .09ms);
  -webkit-animation: motion calc(var(--duration) * .5ms) linear forwards calc(var(--duration) * .19ms);
  animation: motion calc(var(--duration) * .5ms) linear forwards calc(var(--duration) * .19ms);
}

.dl-button.active>div .label>div .counter ul:nth-child(3) {
  --y: -540px;
  -webkit-transition-delay: calc(var(--duration) * .075ms);
  transition-delay: calc(var(--duration) * .075ms);
  -webkit-animation: motion calc(var(--duration) * .8ms) linear forwards calc(var(--duration) * .075ms);
  animation: motion calc(var(--duration) * .8ms) linear forwards calc(var(--duration) * .075ms);
}

.dl-button.active>div .progress {
  --s: 1;
  -webkit-transition-delay: .4s;
  transition-delay: .4s;
}

.dl-button.active>div .progress:after {
  --s: 1;
  -webkit-transition-delay: .4s;
  transition-delay: .4s;
}

.dl-button.done>div .icon {
  --color: var(--success);
}

.dl-button.done .label {
  --color: var(--success);
}

.dl-button.done .label .counter {
  width: 0;
}

@-webkit-keyframes arrow {
  38% {
    -webkit-transform: translateY(100%);
    transform: translateY(100%);
    opacity: 1;
  }

  39% {
    -webkit-transform: translateY(100%);
    transform: translateY(100%);
    opacity: 0;
  }

  40% {
    -webkit-transform: translateY(-100%);
    transform: translateY(-100%);
    opacity: 0;
  }

  41% {
    -webkit-transform: translateY(-100%);
    transform: translateY(-100%);
    opacity: 1;
  }

  100% {
    -webkit-transform: translateY(-1px);
    transform: translateY(-1px);
    opacity: 1;
  }
}

@keyframes arrow {
  38% {
    -webkit-transform: translateY(100%);
    transform: translateY(100%);
    opacity: 1;
  }

  39% {
    -webkit-transform: translateY(100%);
    transform: translateY(100%);
    opacity: 0;
  }

  40% {
    -webkit-transform: translateY(-100%);
    transform: translateY(-100%);
    opacity: 0;
  }

  41% {
    -webkit-transform: translateY(-100%);
    transform: translateY(-100%);
    opacity: 1;
  }

  100% {
    -webkit-transform: translateY(-1px);
    transform: translateY(-1px);
    opacity: 1;
  }
}

@-webkit-keyframes span {
  25% {
    -webkit-transform: translateY(2px) scale(var(--s));
    transform: translateY(2px) scale(var(--s));
  }

  55% {
    -webkit-transform: translateY(2px) scale(var(--s));
    transform: translateY(2px) scale(var(--s));
  }

  80%,
  100% {
    -webkit-transform: translateY(0) scale(var(--s));
    transform: translateY(0) scale(var(--s));
  }
}

@keyframes span {
  25% {
    -webkit-transform: translateY(2px) scale(var(--s));
    transform: translateY(2px) scale(var(--s));
  }

  55% {
    -webkit-transform: translateY(2px) scale(var(--s));
    transform: translateY(2px) scale(var(--s));
  }

  80%,
  100% {
    -webkit-transform: translateY(0) scale(var(--s));
    transform: translateY(0) scale(var(--s));
  }
}

@-webkit-keyframes motion {

  20%,
  70% {
    -webkit-filter: blur(0.4px);
    filter: blur(0.4px);
  }
}

@keyframes motion {

  20%,
  70% {
    -webkit-filter: blur(0.4px);
    filter: blur(0.4px);
  }
}

@-webkit-keyframes button {
  0% {
    -webkit-transform: translateX(0) translateZ(0) scale(1) rotateY(0deg);
    transform: translateX(0) translateZ(0) scale(1) rotateY(0deg);
  }

  10% {
    -webkit-transform: translateX(0) translateZ(0) scale(0.96) rotateY(0deg);
    transform: translateX(0) translateZ(0) scale(0.96) rotateY(0deg);
    box-shadow: 0 4px 8px var(--shadow-dark);
  }

  20% {
    -webkit-transform: translateX(-16px) translateZ(32px) scale(1) rotateY(-16deg);
    transform: translateX(-16px) translateZ(32px) scale(1) rotateY(-16deg);
    box-shadow: 4px 12px 20px var(--shadow-dark);
  }

  85% {
    -webkit-transform: translateX(16px) translateZ(32px) scale(1) rotateY(16deg);
    transform: translateX(16px) translateZ(32px) scale(1) rotateY(16deg);
    box-shadow: -4px 12px 20px var(--shadow-dark);
  }

  95% {
    -webkit-transform: translateX(0) translateZ(0) scale(1.12) rotateY(0deg);
    transform: translateX(0) translateZ(0) scale(1.12) rotateY(0deg);
    box-shadow: 0 8px 24px var(--shadow-dark);
  }

  100% {
    -webkit-transform: translateX(0) translateZ(0) scale(1) rotateY(0deg);
    transform: translateX(0) translateZ(0) scale(1) rotateY(0deg);
  }
}

@keyframes button {
  0% {
    -webkit-transform: translateX(0) translateZ(0) scale(1) rotateY(0deg);
    transform: translateX(0) translateZ(0) scale(1) rotateY(0deg);
  }

  10% {
    -webkit-transform: translateX(0) translateZ(0) scale(0.96) rotateY(0deg);
    transform: translateX(0) translateZ(0) scale(0.96) rotateY(0deg);
    box-shadow: 0 4px 8px var(--shadow-dark);
  }

  20% {
    -webkit-transform: translateX(-16px) translateZ(32px) scale(1) rotateY(-16deg);
    transform: translateX(-16px) translateZ(32px) scale(1) rotateY(-16deg);
    box-shadow: 4px 12px 20px var(--shadow-dark);
  }

  85% {
    -webkit-transform: translateX(16px) translateZ(32px) scale(1) rotateY(16deg);
    transform: translateX(16px) translateZ(32px) scale(1) rotateY(16deg);
    box-shadow: -4px 12px 20px var(--shadow-dark);
  }

  95% {
    -webkit-transform: translateX(0) translateZ(0) scale(1.12) rotateY(0deg);
    transform: translateX(0) translateZ(0) scale(1.12) rotateY(0deg);
    box-shadow: 0 8px 24px var(--shadow-dark);
  }

  100% {
    -webkit-transform: translateX(0) translateZ(0) scale(1) rotateY(0deg);
    transform: translateX(0) translateZ(0) scale(1) rotateY(0deg);
  }
}

.dl-button.done+.restart {
  opacity: 1;
  visibility: visible;
}

.restart {
  --grey-dark: #3F4656;
  position: absolute;
  bottom: 20%;
  left: 50%;
  -webkit-transform: translateX(-50%);
  transform: translateX(-50%);
  color: var(--grey-dark);
  font-size: 14px;
  line-height: 16px;
  text-decoration: none;
  opacity: 0;
  visibility: hidden;
  -webkit-transition: opacity .4s ease;
  transition: opacity .4s ease;
}

.restart svg {
  width: 16px;
  height: 16px;
  margin-right: 4px;
  display: inline-block;
  vertical-align: top;
}

JS (JQuery)

Подключаем JQuery

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

$('.dl-button').on('click', e => {

  let btn = $(e.currentTarget),
    label = btn.find('.label'),
    counter = label.find('.counter');

  if (!btn.hasClass('active') && !btn.hasClass('done')) {

    btn.addClass('active');

    setLabel(label, label.find('.default'), label.find('.state'));

    setTimeout(() => {
      counter.addClass('hide');
      counter.animate({
        width: 0
      }, 400, function () {
        label.width(label.find('.state > span').width());
        counter.removeAttr('style');
      });
      btn.removeClass('active').addClass('done');
    }, getComputedStyle(btn[0]).getPropertyValue('--duration'));

  }

  return false;

});

$('.restart').on('click', e => {

  let btn = $('.dl-button'),
    label = btn.find('.label'),
    counter = label.find('.counter');

  setLabel(label, label.find('.state'), label.find('.default'), function () {
    counter.removeClass('hide');
    btn.removeClass('done');
  });

  return false;

});

function setLabel(div, oldD, newD, callback) {
  oldD.addClass('hide');
  div.animate({
    width: newD.outerWidth()
  }, 200, function () {
    oldD.removeClass('show hide');
    newD.addClass('show');
    div.removeAttr('style');
    if (typeof callback === 'function') {
      callback();
    }
  });
}

Источник
Оцените статью
( Пока оценок нет )
Поделишься в соц. сетях? 🙂 Спасибо 🙏
Devtutor
Добавить комментарий