Как сделать анимацию кнопки spark?

107
04 октября 2019, 09:40

Я только что нашел на GitHub Repo, на котором есть отличная анимация для кнопки, но для Android.

Вот эта анимация:

Тем не менее, я хочу такую же кнопку для своего сайта, поэтому я начал разрабатывать это сам.

Во-первых, я разбил гифку по кадрам.

И затем по этим кадрам я составил дорожную карту, которой я следую при написании кода:

  • Звезда постепенно scale() уменьшается.
  • Маленький кружок оранжевого цвета постепенно покрывает звезду при увеличении.
  • Еще один маленький кружок, но на этот раз цвета фона (в данном случае белый), постепенно перекрывает предыдущий кружок также увеличением масштаба.
  • Наряду с этим звезда также постепенно увеличивается снова и снова появляясь (таким образом, я должен увеличить z-index), на этот раз оранжевого цвета (Указывая на ее выбранное состояние).
  • Есть еще маленькие кружочки, разбросанные со всех сторон новой звезды.

Это то, что получилось у меня:

svg { 
  position: absolute; 
  top: 0; 
  width: 100px; 
  height: 100px; 
  transition: 0.5s; 
  fill:gray; 
} 
 
svg:hover { 
  animation: up-svg 1s; 
  fill: darkorange; 
  z-index: 1; 
} 
 
svg:hover~.svg { 
  animation: up-one 0.5s; 
  display: block; 
} 
 
svg:hover~.svg1 { 
  animation: up-two 1s; 
  display: block; 
} 
 
.svg { 
  position: absolute; 
  top: 0; 
  border-radius: 50%; 
  width: 100px; 
  height: 100px; 
  background-color: orange; 
  display: none; 
  transform: scale(0.9); 
  transition: 0.5s; 
} 
 
.svg1 { 
  position: absolute; 
  top: 0; 
  border-radius: 50%; 
  width: 100px; 
  height: 100px; 
  background-color: white; 
  display: none; 
  transition: 0.5s; 
} 
 
@keyframes up-one { 
  0% { 
    transform: scale(0); 
  } 
  40% { 
    transform: scale(0); 
  } 
  100% { 
    transform: scale(0.9); 
  } 
} 
 
@keyframes up-two { 
  0% { 
    transform: scale(0); 
  } 
  37.5% { 
    transform: scale(0); 
  } 
  50% { 
    transform: scale(0.25); 
  } 
  62.5% { 
    transform: scale(0.5); 
  } 
  75% { 
    transform: scale(0.75); 
  } 
  87.5% { 
    transform: scale(0.9); 
  } 
  100% { 
    transform: scale(1); 
  } 
} 
 
@keyframes up-svg { 
  0% { 
    transform: scale(1); 
    fill: gray; 
    z-index: 0; 
  } 
  70% { 
    transform: scale(0); 
    fill: darkorange; 
    z-index: 1; 
  } 
  100% { 
    transform: scale(1); 
    fill: darkorange; 
    z-index: 1; 
  } 
}
<svg id="s-tt" class="s-icon" role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M23.954 4.569c-.885.389-1.83.654-2.825.775 1.014-.611 1.794-1.574 2.163-2.723-.951.555-2.005.959-3.127 1.184-.896-.959-2.173-1.559-3.591-1.559-2.717 0-4.92 2.203-4.92 4.917 0 .39.045.765.127 1.124C7.691 8.094 4.066 6.13 1.64 3.161c-.427.722-.666 1.561-.666 2.475 0 1.71.87 3.213 2.188 4.096-.807-.026-1.566-.248-2.228-.616v.061c0 2.385 1.693 4.374 3.946 4.827-.413.111-.849.171-1.296.171-.314 0-.615-.03-.916-.086.631 1.953 2.445 3.377 4.604 3.417-1.68 1.319-3.809 2.105-6.102 2.105-.39 0-.779-.023-1.17-.067 2.189 1.394 4.768 2.209 7.557 2.209 9.054 0 13.999-7.496 13.999-13.986 0-.209 0-.42-.015-.63.961-.689 1.8-1.56 2.46-2.548l-.047-.02z"/></svg> 
<div class="svg"></div> 
<div class="svg1"></div>

Я пробовал, но все же результат не похож на ожидаемый, и я застрял с этими кругами рассеяния тоже.
Цвета не являются приоритетом прямо сейчас. И я придерживаюсь свойства hover (чтобы анимация была видна снова и снова без перезагрузки), пока анимация не будет доведена до конца.

Я искал решения в Google и SO, но пока не повезло.
Итак, кто-нибудь поможет мне сделать такую анимацию?

UPDATE

Добавляю ссылку на spark анимацию от известного мастера Ana Tudor

Answer 1

Вот моя не идеальная идея, где я буду полагаться только на CSS и немного элементов. Я подробно опишу каждую часть, а затем объединю это в одну анимацию.

Для части с иконкой (звездочкой) я бы сделал то же самое, как у вас, но я, вероятно, рассмотрю фильтр в оттенках серого, чтобы иметь общий эффект, который работает с любым элементом и любым цветом.

.magic i{ 
  color:red; 
  filter:grayscale(100%); 
} 
.magic:hover i{ 
  animation:change 1s forwards; 
} 
 
 
@keyframes change{ 
  50% { 
    transform:scale(0); 
  filter:grayscale(100%); 
  } 
  51% { 
    filter:grayscale(0%); 
  } 
  100% { 
    transform:scale(1); 
    filter:grayscale(0%); 
  } 
}
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.7.1/css/all.css"> 
<span class="magic"> 
<i class="fas fa-star fa-5x"></i> 
</span>

Для круга я рассмотрю только один элемент, и хитрость здесь заключается в том, чтобы полагаться на окраску border по сравнению с окраской background.

Мы изначально устанавливаем height/width равной нулю, и у нас есть только border, поэтому это будет полный круг.

Затем мы просто уменьшаем толщину border, сохраняя общую ширину одинаковой. Итак, мы сделаем:

  1. Начальная форма width/height - 0 and border-width - 0

  2. Мы увеличиваем border-width, чтобы создать эффект увеличения

  3. Мы уменьшаем border-width, увеличивая при этом width/height, чтобы сохранить общую width/height одинаковой.

.circle { 
  display:inline-block; 
  width:0px; 
  height:0px; 
  border-radius:50%; 
  border-color:orange; 
  border-style:solid; 
  border-width:0px; 
  box-sizing:border-box; 
} 
 
body:hover .circle { 
  animation:change 1s forwards; 
} 
 
@keyframes change { 
   50% { 
    border-width:25px; 
   } 
   100% { 
    border-width:0; 
    width:50px; 
    height:50px; 
   } 
 
} 
 
body { 
 min-height:100px; 
}
<span class="circle"></span>

Это решение имеет небольшой недостаток, так как элемент будет увеличиваться сверху слева, а не по центру. Мы можем исправить это, используя scale вместо изменения width/height:

.circle { 
  display:inline-block; 
  width:50px; 
  height:50px; 
  border-radius:50%; 
  border-color:orange; 
  border-style:solid; 
  border-width:25px; 
  transform:scale(0); 
  box-sizing:border-box; 
} 
 
body:hover .circle { 
  animation:change 1s linear forwards; 
} 
 
@keyframes change { 
   50% { 
    transform:scale(1); 
    border-width:25px; 
   } 
   100% { 
    transform:scale(1); 
    border-width:0; 
   } 
 
} 
 
body { 
 min-height:100px; 
}
<span class="circle"></span>

Мы можем упростить рассмотрение простого transition:

.circle { 
  display:inline-block; 
  width:50px; 
  height:50px; 
  border-radius:50%; 
  border-color:orange; 
  border-style:solid; 
  border-width:25px; 
  transform:scale(0); 
  box-sizing:border-box; 
  transition: 
    transform 0.5s, 
    border-width 0.5s 0.5s; 
} 
 
body:hover .circle { 
  border-width:0; 
  transform:scale(1); 
} 
 
body { 
 min-height:100px; 
}
<span class="circle"></span>

Теперь сложная часть анимации и добавление маленьких кругов. Для этого я буду полагаться на radial-gradient и scale. Идея состоит в том, чтобы создать маленькие круги с градиентом внутри одного элемента, и используя scale, мы создадим эффект их увеличения и движения.

.small { 
  display:inline-block; 
  width:100px; 
  height:100px; 
  background: 
    /*4 reds*/ 
    radial-gradient(circle,red 50%,transparent 60%), 
    radial-gradient(circle,red 50%,transparent 60%), 
    radial-gradient(circle,red 50%,transparent 60%), 
    radial-gradient(circle,red 50%,transparent 60%), 
    /*4 oranges*/ 
    radial-gradient(circle,orange 50%,transparent 60%), 
    radial-gradient(circle,orange 50%,transparent 60%), 
    radial-gradient(circle,orange 50%,transparent 60%), 
    radial-gradient(circle,orange 50%,transparent 60%);  
   
  background-size:16px 16px;  
  background-position: 
    calc(50% - 30px) calc(50% - 30px), 
    calc(50% + 30px) calc(50% - 30px), 
    calc(50% - 30px) calc(50% + 30px), 
    calc(50% + 30px) calc(50% + 30px), 
    calc(50% +  0px) calc(50% + 40px), 
    calc(50% + 40px) calc(50% +  0px), 
    calc(50% - 40px) calc(50% +  0px), 
    calc(50% +  0px) calc(50% - 40px); 
  background-repeat:no-repeat; 
  border-radius:50%; 
}
<span class="small"></span>

Я создал 8 кругов и разместил их, смещая их от центра (посмотрите этот ответ, чтобы узнать больше о том, как работает background-position: https://stackoverflow.com/a/51734530/8620333

Вам просто нужно настроить размер, положение и цвет круга, как вам необходимо.

А вот с анимацией:

.small { 
  display:inline-block; 
  width:100px; 
  height:100px; 
  background: 
    /*4 reds*/ 
    radial-gradient(circle,red 50%,transparent 60%), 
    radial-gradient(circle,red 50%,transparent 60%), 
    radial-gradient(circle,red 50%,transparent 60%), 
    radial-gradient(circle,red 50%,transparent 60%), 
    /*4 oranges*/ 
    radial-gradient(circle,orange 50%,transparent 60%), 
    radial-gradient(circle,orange 50%,transparent 60%), 
    radial-gradient(circle,orange 50%,transparent 60%), 
    radial-gradient(circle,orange 50%,transparent 60%);  
   
  background-size:16px 16px; 
  background-position: 
    calc(50% - 30px) calc(50% - 30px), 
    calc(50% + 30px) calc(50% - 30px), 
    calc(50% - 30px) calc(50% + 30px), 
    calc(50% + 30px) calc(50% + 30px), 
    calc(50% +  0px) calc(50% + 40px), 
    calc(50% + 40px) calc(50% +  0px), 
    calc(50% - 40px) calc(50% +  0px), 
    calc(50% +  0px) calc(50% - 40px); 
  background-repeat:no-repeat; 
  border-radius:50%; 
  transform:scale(0); 
  transition:transform 0.5s,opacity 0.4s 0.4s; 
} 
 
body { 
 min-height:200px; 
} 
body:hover .small { 
  transform:scale(1); 
  opacity:0; 
}
<span class="small"></span>

Если вы хотите более точную анимацию, вы также можете уменьшить круги, уменьшив background-size.

.small { 
  display:inline-block; 
  width:100px; 
  height:100px; 
  background: 
    /*4 reds*/ 
    radial-gradient(circle,red 50%,transparent 60%), 
    radial-gradient(circle,red 50%,transparent 60%), 
    radial-gradient(circle,red 50%,transparent 60%), 
    radial-gradient(circle,red 50%,transparent 60%), 
    /*4 oranges*/ 
    radial-gradient(circle,orange 50%,transparent 60%), 
    radial-gradient(circle,orange 50%,transparent 60%), 
    radial-gradient(circle,orange 50%,transparent 60%), 
    radial-gradient(circle,orange 50%,transparent 60%);  
   
  background-size:16px 16px; /*at least 2x7px */ 
  background-position: 
    calc(50% - 30px) calc(50% - 30px), 
    calc(50% + 30px) calc(50% - 30px), 
    calc(50% - 30px) calc(50% + 30px), 
    calc(50% + 30px) calc(50% + 30px), 
    calc(50% +  0px) calc(50% + 40px), 
    calc(50% + 40px) calc(50% +  0px), 
    calc(50% - 40px) calc(50% +  0px), 
    calc(50% +  0px) calc(50% - 40px); 
  background-repeat:no-repeat; 
  border-radius:50%; 
  transform:scale(0); 
  transition:transform 0.5s,opacity 0.4s 0.4s,background-size 0.5s 0.4s; 
} 
 
body { 
 min-height:200px; 
} 
body:hover .small { 
  transform:scale(1); 
  opacity:0; 
  background-size:0 0; 
}
<span class="small"></span>

Теперь вы просто делаете то же самое с другими маленькими кружками, изменяя некоторые значения.

Давайте соединим все это!

.magic { 
  display:inline-block; 
  margin:50px; 
  position:relative; 
} 
 
.magic i{ 
  color:orange; 
  filter:grayscale(100%); 
  position:relative; 
} 
.magic:hover i{ 
  animation:change 1s forwards; 
} 
 
 
@keyframes change{ 
  50% { 
    transform:scale(0); 
  filter:grayscale(100%); 
  } 
  51% { 
    filter:grayscale(0%); 
  } 
  100% { 
    transform:scale(1); 
    filter:grayscale(0%); 
  } 
} 
/**/ 
 
.magic:before { 
  content:""; 
  position:absolute; 
  top:calc(50% - 45px); 
  left:calc(50% - 45px); 
  width:90px; 
  height:90px; 
  border-radius:50%; 
  border-color:orange; 
  border-style:solid; 
  border-width:45px; 
  transform:scale(0); 
  box-sizing:border-box; 
} 
 
.magic:hover::before { 
  transition: 
    transform 0.5s, 
    border-width 0.5s 0.5s; 
  border-width:0; 
  transform:scale(1); 
} 
 
/**/ 
 
.magic::after { 
  content:""; 
  position:absolute; 
  width:160px; 
  height:160px; 
  left:calc(50% - 80px); 
  top:calc(50% - 80px); 
  background: 
    /*4 reds*/ 
    radial-gradient(circle,red 50%,transparent 60%), 
    radial-gradient(circle,red 50%,transparent 60%), 
    radial-gradient(circle,red 50%,transparent 60%), 
    radial-gradient(circle,red 50%,transparent 60%), 
    /*4 oranges*/ 
    radial-gradient(circle,orange 50%,transparent 60%), 
    radial-gradient(circle,orange 50%,transparent 60%), 
    radial-gradient(circle,orange 50%,transparent 60%), 
    radial-gradient(circle,orange 50%,transparent 60%);  
   
  background-size:16px 16px;  
  background-position: 
    calc(50% - 50px) calc(50% - 50px), 
    calc(50% + 50px) calc(50% - 50px), 
    calc(50% - 50px) calc(50% + 50px), 
    calc(50% + 50px) calc(50% + 50px), 
    calc(50% +  0px) calc(50% + 70px), 
    calc(50% + 70px) calc(50% +  0px), 
    calc(50% - 70px) calc(50% +  0px), 
    calc(50% +  0px) calc(50% - 70px); 
  background-repeat:no-repeat; 
  border-radius:50%; 
  transform:scale(0); 
} 
 
.magic:hover:after { 
  transform:scale(1); 
  opacity:0; 
  background-size:0 0; 
  transition: 
    transform 0.5s 0.5s, 
    opacity 0.4s 0.9s, 
    background-size 0.5s 0.9s; 
}
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.7.1/css/all.css"> 
<span class="magic"> 
<i class="fas fa-star fa-5x"></i> 
</span> 
 
<span class="magic"> 
<i class="fas fa-user fa-5x"></i> 
</span>

Как я уже сказал, он не идеален, но очень близок к тому, что вы хотите, с меньшим количеством элементов и необходимыми деталями, так что вы можете легко настроить различные значения.

Я не добавил крошечные круги для простоты, но мы можем рассмотреть другой псевдоэлемент и легко добавить их:

.magic { 
  display:inline-block; 
  margin:50px; 
  position:relative; 
} 
 
.magic i{ 
  color:orange; 
  filter:grayscale(100%); 
} 
.magic:hover i{ 
  animation:change 1s forwards; 
} 
 
 
@keyframes change{ 
  50% { 
    transform:scale(0); 
  filter:grayscale(100%); 
  } 
  51% { 
    filter:grayscale(0%); 
  } 
  100% { 
    transform:scale(1); 
    filter:grayscale(0%); 
  } 
} 
/**/ 
 
.magic:before { 
  content:""; 
  position:absolute; 
  top:calc(50% - 45px); 
  left:calc(50% - 45px); 
  width:90px; 
  height:90px; 
  border-radius:50%; 
  border-color:orange; 
  border-style:solid; 
  border-width:45px; 
  transform:scale(0); 
  box-sizing:border-box; 
} 
 
.magic:hover::before { 
  border-width:0; 
  transform:scale(1); 
  transition: 
    transform 0.5s, 
    border-width 0.5s 0.5s; 
} 
 
/**/ 
 
.magic::after, 
.magic i::after{ 
  content:""; 
  position:absolute; 
  width:160px; 
  height:160px; 
  left:calc(50% - 80px); 
  top:calc(50% - 80px); 
  background: 
    /*4 reds*/ 
    radial-gradient(circle,red 50%,transparent 60%), 
    radial-gradient(circle,red 50%,transparent 60%), 
    radial-gradient(circle,red 50%,transparent 60%), 
    radial-gradient(circle,red 50%,transparent 60%), 
    /*4 oranges*/ 
    radial-gradient(circle,orange 50%,transparent 60%), 
    radial-gradient(circle,orange 50%,transparent 60%), 
    radial-gradient(circle,orange 50%,transparent 60%), 
    radial-gradient(circle,orange 50%,transparent 60%);  
   
  background-size:16px 16px;  
  background-position: 
    calc(50% - 50px) calc(50% - 50px), 
    calc(50% + 50px) calc(50% - 50px), 
    calc(50% - 50px) calc(50% + 50px), 
    calc(50% + 50px) calc(50% + 50px), 
    calc(50% +  0px) calc(50% + 70px), 
    calc(50% + 70px) calc(50% +  0px), 
    calc(50% - 70px) calc(50% +  0px), 
    calc(50% +  0px) calc(50% - 70px); 
  background-repeat:no-repeat; 
  border-radius:50%; 
  transform:scale(0); 
} 
.magic i::after { 
  background-size:10px 10px; 
  transform:rotate(10deg) scale(0); 
} 
 
.magic:hover:after { 
  transform:scale(1); 
  opacity:0; 
  background-size:0 0; 
  transition:transform 0.5s 0.5s,opacity 0.4s 0.9s,background-size 0.5s 0.9s; 
} 
.magic:hover i:after { 
  transform:rotate(10deg) scale(1); 
  opacity:0; 
  background-size:0 0; 
  transition:transform 0.5s 0.5s,opacity 0.4s 0.9s,background-size 0.5s 0.9s; 
} 
 
/**/
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.7.1/css/all.css"> 
<span class="magic"> 
<i class="fas fa-star fa-5x"></i> 
</span> 
 
<span class="magic"> 
<i class="fas fa-user fa-5x"></i> 
</span>

UPDATE

Вот улучшение кода, учитывающее некоторую переменную CSS и использующее более гибкий модуль для простого управления позиционированием:

.magic { 
  display:inline-block; 
  margin:50px; 
  position:relative; 
  --r:45px; 
} 
 
.magic i{ 
  color:orange; 
  filter:grayscale(100%); 
} 
.magic:hover i{ 
  animation:change 1s forwards; 
} 
 
 
@keyframes change{ 
  50% { 
   transform:scale(0); 
   filter:grayscale(100%); 
  } 
  51% { 
    filter:grayscale(0%); 
  } 
  100% { 
    transform:scale(1); 
    filter:grayscale(0%); 
  } 
} 
/**/ 
 
.magic:before { 
  content:""; 
  position:absolute; 
  top:calc(50% - var(--r)); 
  left:calc(50% - var(--r)); 
  width:calc(2*var(--r)); 
  height:calc(2*var(--r)); 
  border-radius:50%; 
  border:solid orange var(--r); 
  transform:scale(0); 
  box-sizing:border-box; 
} 
 
.magic:hover::before { 
  border-width:0; 
  transform:scale(1); 
  transition: 
    transform 0.5s, 
    border-width 0.5s 0.5s; 
} 
 
/**/ 
 
.magic::after, 
.magic i::after{ 
  content:""; 
  position:absolute; 
  width: calc(4*var(--r)); 
  height:calc(4*var(--r)); 
  left:calc(50% - 2*var(--r)); 
  top: calc(50% - 2*var(--r)); 
  --c1:radial-gradient(circle,red 50%   ,transparent 60%); 
  --c2:radial-gradient(circle,orange 50%,transparent 60%); 
  background: 
    /*4 reds*/ 
    var(--c1),var(--c1),var(--c1),var(--c1), 
    /*4 oranges*/ 
    var(--c2),var(--c2),var(--c2),var(--c2);  
   
  background-size:calc(var(--r)/3) calc(var(--r)/3);  
  background-position: 
    calc(50% - var(--r)) calc(50% - var(--r)), 
    calc(50% + var(--r)) calc(50% - var(--r)), 
    calc(50% - var(--r)) calc(50% + var(--r)), 
    calc(50% + var(--r)) calc(50% + var(--r)), 
    calc(50% +  0px) calc(50% + var(--r)*1.414), 
    calc(50% + var(--r)*1.414) calc(50% +  0px), 
    calc(50% - var(--r)*1.414) calc(50% +  0px), 
    calc(50% +  0px) calc(50% - var(--r)*1.414); 
  background-repeat:no-repeat; 
  transform:scale(0); 
} 
.magic i::after { 
  background-size:calc(var(--r)/5) calc(var(--r)/5); 
  transform:rotate(55deg) scale(0); 
} 
 
.magic:hover:after { 
  transform:scale(1); 
  opacity:0; 
  background-size:0 0; 
  transition: 
    transform 0.5s 0.5s, 
    opacity 0.4s 0.9s, 
    background-size 0.5s 0.9s; 
} 
.magic:hover i:after { 
  transform:rotate(55deg) scale(1); 
  opacity:0; 
  background-size:0 0; 
  transition: 
    transform 0.5s 0.5s, 
    opacity 0.4s 0.9s, 
    background-size 0.5s 0.9s; 
} 
 
/**/
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.7.1/css/all.css"> 
<span class="magic" style="--r:80px;"> 
<i class="fas fa-star fa-10x"></i> 
</span> 
<span class="magic"> 
<i class="fas fa-user fa-5x"></i> 
</span> 
<span class="magic" style="--r:20px;"> 
<i class="far fa-bell fa-3x"></i> 
</span>

В основном, переменная r будет определять радиус всей фигуры, и вы можете легко изменить ее в зависимости от размера вашей иконки.

READ ALSO
Google Charts: Pie Chart. Длина линий

Google Charts: Pie Chart. Длина линий

Есть ли возможность как либо уменьшить длину линий в Pie Chart при включенной опции legendposition='labeled' ? На данный момент линии перекрывают текст на срезах...

119
не корректно прекращается css анимация

не корректно прекращается css анимация

Добавляю анимацию с этой библиотеки https://githubcom/daneden/animate

89
Не появляются элементы при нажатии [JS]

Не появляются элементы при нажатии [JS]

Помогите разобраться почему не рисуются крестики в квадратиках по нажатию? Нужно что бы при нажатии на каждый квадратик - там появлялся крестик,...

100