Как сделать эффект трещины у текста

287
02 апреля 2018, 22:01

Данный Q-A является продолжением прошлого(стилизация текста SVG).

В этом Q-A(Question-Answer) мы рассмотрим Crack effect, ниже будут приведены примеры этого эффекта, всего их будет 3 штуки.

Первый пример (появление трещины вдоль текста с дальнейшей трансформацией):

Второй пример (верхняя часть текста отламывается и плавно съезжает после взмаха мечом, при том, что сам текст должен находится под наклоном примерно в 1-2deg):

Третий пример (похож на второй, но есть своё отличие, происходит два взмаха вдоль и поперёк текста):

Текст будет реализован на SVG, его размещение через clipPath, а анимация с помощью @keyframes.

P.S. Все примеры срабатывают после клика.

Answer 1
Первый пример:
  • Обе части текста находятся в rect, сам текст мы вставляем в них с помощью clipPath, а затем позиционируем их по оси Y, вот пример позиционирования первой и второй половины текста:

* { 
  margin: 0; 
  padding: 0; 
} 
 
body { 
  background-color: #000000; 
  display: flex; 
  justify-content: center; 
  align-items: center; 
} 
 
svg text { 
  font-family: 'Russo One', sans-serif; 
  text-transform: uppercase; 
  font-size: 5em; 
  pointer-events: none; 
  user-select: none; 
}
<link href="https://fonts.googleapis.com/css?family=Russo+One" rel="stylesheet"> 
<svg width="710" height="200" viewBox="0 0 710 200" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> 
  <defs> 
    <clipPath id="clip"> 
      <text text-anchor="middle" x="50%" y="50%">Breaking text</text> 
    </clipPath> 
  </defs> 
  <rect id="top" class="rectangle" clip-path="url(#clip)" width="710" height="50" fill="white"> 
  <!--Смещение по оси Y--> 
  <animate attributeName="y" values="-10;26;-10" dur="3s" repeatCount="indefinite"/> 
  </rect> 
  <rect id="bottom" class="rectangle" clip-path="url(#clip)" width="710" height="50" fill="white"> 
  <!--Смещение по оси Y--> 
  <animate attributeName="y" values="103;75;103" dur="3s" repeatCount="indefinite"/> 
  </rect> 
</svg>

  • После позиционирования текста сделаем простую анимацию, используя CSS-свойство - transform и добавим transition, а именно cubic-bezier. Но сначала мы пройдемся по каждому rect'у и дадим им класс active:

function crack() { 
  var rect = document.getElementsByTagName("rect"); 
  Array.from(rect).forEach(x => x.classList.toggle("active")); 
}
* { 
  margin: 0; 
  padding: 0; 
} 
 
body { 
  background-color: #000000; 
  display: flex; 
  justify-content: center; 
  align-items: center; 
} 
 
svg text { 
  font-family: 'Russo One', sans-serif; 
  text-transform: uppercase; 
  font-size: 5em; 
  pointer-events: none; 
  user-select: none; 
} 
 
svg rect { 
  transition: cubic-bezier(0.1, 0.3, 0.5, 1) .1s; 
} 
 
rect.active { 
  transform: translateX(-3px) rotate(-0.15deg); 
} 
 
rect.active:last-child { 
  transform: translateX(3px) rotate(0.15deg); 
}
<link href="https://fonts.googleapis.com/css?family=Russo+One" rel="stylesheet"> 
<svg width="710" height="200" viewBox="0 0 710 200" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> 
  <defs> 
    <clipPath id="clip"> 
      <text text-anchor="middle" x="50%" y="50%">Breaking text</text> 
    </clipPath> 
  </defs> 
  <g onclick="crack()"> 
    <rect id="top" class="rectangle" clip-path="url(#clip)" width="710" height="50" y="26" fill="white"/> 
    <rect id="bottom" class="rectangle" clip-path="url(#clip)" width="710" height="50" y="75" fill="white"/> 
  </g> 
</svg>

Answer 2
Третий пример:
  • Вместо двух rect мы будем использовать четыре, для каждых двух частей я сделал по clipPath( не нашёл способа лучше, буду рад предложениям, как сделать это "чище":) ):
    P.S. Примерно то, что мы должны получить.

* { 
  margin: 0; 
  padding: 0; 
} 
 
body { 
  background-color: #000000; 
  display: flex; 
  justify-content: center; 
  align-items: center; 
  flex-direction: column; 
} 
 
svg rect { 
  fill: white; 
}
<svg viewBox="-30 0 740 200" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> 
  <!-- FOUR RECTS --> 
  <g> 
    <rect clip-path="url(#clip)" width="336" height="50" y="26"> 
      <animateTransform attributeName="transform" type="translate" values="0 0; -20 -20; 0 0" dur="3s" repeatCount="indefinite"/> 
    </rect> 
    <rect clip-path="url(#clip)" width="336" height="50" y="75"> 
      <animateTransform attributeName="transform" type="translate" values="0 0; -20 20; 0 0" dur="3s" repeatCount="indefinite"/> 
    </rect> 
    <rect clip-path="url(#clip)" width="336" height="50" x="336" y="26"> 
      <animateTransform attributeName="transform" type="translate" values="0 0; 20 -20; 0 0" dur="3s" repeatCount="indefinite"/>  
    </rect> 
    <rect clip-path="url(#clip)" width="336" x="336" height="50" y="75"> 
      <animateTransform attributeName="transform" type="translate" values="0 0; 20 20; 0 0" dur="3s" repeatCount="indefinite"/>  
    </rect> 
  </g> 
</svg>

  • Все три примера между собой похожи, поэтому нет надобности повторно говорить, что к имитации взмаха и к остальным rect( не сочтите за лень:))) ) добавляются классы, собственно вот, воззрите:

function doubleCrack() { 
  var rect = document.getElementsByTagName("rect"); 
  var polygon = document.getElementById("horizontal"); 
  var polygonTwo = document.getElementById("vertical"); 
 
  polygon.classList.add("_activate"); 
  polygonTwo.classList.add("_activate"); 
 
  Array.from(rect).forEach(x => x.classList.add("_activate-rect")); 
}
* { 
  margin: 0; 
  padding: 0; 
} 
 
body { 
  background-color: #000000; 
  display: flex; 
  justify-content: center; 
  align-items: center; 
  flex-direction: column; 
} 
 
svg text { 
  font-family: "Russo One", sans-serif; 
  text-transform: uppercase; 
  font-size: 5em; 
  pointer-events: none; 
} 
 
svg rect { 
  transition: 2s; 
  transition-delay: 1s; 
  fill: white; 
} 
 
#horizontal { 
  transform: translateX(-100px); 
} 
 
#vertical { 
  transform: translate(335px, 150px); 
} 
 
#horizontal._activate { 
  animation: attack 0.4s 1; 
} 
 
#vertical._activate { 
  animation: attack-2 0.4s 1; 
  animation-delay: 0.4s; 
} 
 
#top._activate-rect { 
	transform: translate(-20px, -20px); 
	opacity: 0; 
} 
 
#bottom._activate-rect { 
	transform: translate(-20px, 20px); 
	opacity: 0; 
} 
 
#topN._activate-rect { 
	transform: translate(20px, -20px); 
	opacity: 0; 
} 
 
#bottomN._activate-rect { 
	transform: translate(20px, 20px); 
	opacity: 0; 
} 
 
@keyframes attack { 
  to { 
    transform: translateX(750px); 
  } 
} 
 
@keyframes attack-2 { 
  to { 
    transform: translateX(335px) translateY(-150px); 
  } 
} 
 
@keyframes break { 
  to { 
    transform: translateX(320px); 
  } 
}
<link href="https://fonts.googleapis.com/css?family=Russo+One" rel="stylesheet"> 
<svg viewBox="0 0 740 200" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> 
  <defs> 
    <!-- FIRST SIDE --> 
    <clipPath id="clip"> 
      <text text-anchor="middle" x="368" y="50%">Breaking text</text> 
    </clipPath> 
    <!-- SECOND SIDE --> 
    <clipPath id="clipN"> 
      <text text-anchor="middle" x="370" y="50%">Breaking text</text> 
    </clipPath> 
  </defs> 
  <!-- FOUR RECTS --> 
  <g onclick="doubleCrack()"> 
    <rect id="top" clip-path="url(#clip)" width="336" height="50" y="26"/> 
    <rect id="bottom" clip-path="url(#clip)" width="336" height="50" y="75"/> 
    <rect id="topN" clip-path="url(#clipN)" width="380" height="50" x="335" y="26"/> 
    <rect id="bottomN" clip-path="url(#clipN)" width="380" height="50" x="335" y="75"/> 
  </g> 
  <!-- SWORDS --> 
  <g>		 
    <polygon id="horizontal" points="0,75 55,67 70,75 56,80" fill="silver"/> 
    <polygon id="vertical" points="0,60 5,68 0,100 -5,68" fill="silver"/> 
  </g> 
</svg>

Answer 3
Второй пример:
  • В этом примере используется то же самое позиционирование, только в добавок нужно повернуть rect'ы на 1deg и после клика добавлять transform: translateX(N):

* { 
  margin: 0; 
  padding: 0; 
} 
 
body { 
  background-color: #000000; 
  display: flex; 
  justify-content: center; 
  align-items: center; 
  flex-direction: column; 
} 
 
svg text { 
  font-family: 'Russo One', sans-serif; 
  text-transform: uppercase; 
  font-size: 4em; 
  pointer-events: none; 
} 
 
svg rect { 
  transform: rotate(-1deg); 
  transition: cubic-bezier(1, 0.3, 0.6, 1) 3.5s; 
} 
 
#top {  
  animation: offsetXF 1s infinite; 
} 
 
#bottom {  
  animation: offsetXT 1s infinite; 
} 
 
@keyframes offsetXF { 
  50% { 
    transform: translateX(-30px) rotate(-1deg); 
    opacity: 0; 
  } 
} 
 
@keyframes offsetXT { 
  50% { 
    transform: translateX(30px) rotate(-1deg); 
    opacity: 0; 
  } 
}
<link href="https://fonts.googleapis.com/css?family=Russo+One" rel="stylesheet"> 
<svg viewBox="0 0 710 200" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> 
  <defs> 
    <clipPath id="clip"> 
      <text text-anchor="middle" x="50%" y="49%">Breaking text</text> 
    </clipPath> 
  </defs> 
  <g> 
  <!--Смещение по оси X--> 
    <rect id="top" clip-path="url(#clip)" width="710" height="50" y="26" fill="white"/> 
    <rect id="bottom" clip-path="url(#clip)" width="710" height="50" y="75" fill="white"/> 
  </g> 
</svg>

  • Осталось сделать polygon, который будет имитировать взмах мечом(или катаной:D), а в финальной версии этого примера мы будем смещать его также по оси X, примерно на 700-800px:

<svg viewBox="0 0 710 200" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> 
  <polygon id="sword" points="0,75 55,67 70,75 56,80" fill="silver" transform="scale(2)"/> 
</svg>

  • Финальная версия. После клика мы меняем местоположение polygon, при этом добавляется класс для #top, из-за чего и происходит смещение верхней части текста, также видна задержка после взмаха, так как у rect добавлен transition-delay:

function crack() { 
  var rect = document.getElementById("top"); 
  var polygon = document.getElementById("sword"); 
  rect.classList.add("active"); 
  polygon.classList.add("_activate"); 
}
* { 
  margin: 0; 
  padding: 0; 
} 
 
body { 
  background-color: #000000; 
  display: flex; 
  justify-content: center; 
  align-items: center; 
  flex-direction: column; 
} 
 
svg text { 
  font-family: 'Russo One', sans-serif; 
  text-transform: uppercase; 
  font-size: 4em; 
  pointer-events: none; 
} 
 
svg rect { 
  transform: rotate(-1deg); 
  transition: cubic-bezier(1, 0.3, 0.6, 1) 3.5s; 
  transition-delay: 1s; 
} 
 
#top.active { 
  transform: translateX(-30px) rotate(-1deg); 
  opacity: 0; 
} 
 
#sword { 
  transform: rotate(-1deg) translateX(-100px); 
} 
 
#sword._activate { 
  animation: attack 0.4s 1; 
} 
 
@keyframes attack { 
  to { 
    transform: rotate(-1deg) translateX(750px); 
  } 
}
<link href="https://fonts.googleapis.com/css?family=Russo+One" rel="stylesheet"> 
<svg viewBox="0 0 710 200" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> 
  <defs> 
    <clipPath id="clip"> 
      <text text-anchor="middle" x="50%" y="49%">Breaking text</text> 
    </clipPath> 
  </defs> 
  <g onclick="crack()"> 
    <rect id="top" clip-path="url(#clip)" width="710" height="50" y="26" fill="white"/> 
    <rect clip-path="url(#clip)" width="710" height="50" y="75" fill="white"/> 
    <polygon id="sword" points="0,75 55,67 70,75 56,80" fill="silver"/> 
  </g> 
</svg>

READ ALSO
Как закрыть меню при клике на его пункт?

Как закрыть меню при клике на его пункт?

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

262
Как передать данные таблицы html в функцию

Как передать данные таблицы html в функцию

Всем доброго времени сутокПроблема такая, у меня есть таблица html, нужно эту таблицу экспортировать в excel

214
Подписи к картинке в html

Подписи к картинке в html

Как реализовать такие подписи к картинке?

232
Скидывает пароль на Mysl server&#39;е

Скидывает пароль на Mysl server'е

Установил Mysql server всё работало нормально и щас такие проблемы: поставил пароль свой, пару дней нормально заходит, а потом захожу и пароль видимо...

252