Как стать автором
Обновить

Создаем glitch-эффект как в Cyberpunk 2077 для изображения с помощью CSS

Время на прочтение 4 мин
Количество просмотров 19K
Photo by Hyunwon Jang on Unsplash
Photo by Hyunwon Jang on Unsplash

Зайдя на сайт Cyberpunk 2077 в раздел новостей, я наткнулся на "тот самый" эффект. Он появлялся при наведении на изображение поста. Мне показалось это интересным и я решил посмотреть как это работает. В этом посте я хотел бы поделиться тем, что нарыл.

Для достижения этого эффекта, нам необходимо 2 раза вывести изображение, наложив их друг на друга. Сам эффект будет проявляться на изображении, которое лежит сверху.

Итак, создаем контейнер с двумя изображениями. Сами изображения будут добавлены как фон.

<div class="container">
  <div class="img"></div>
  <div class="glitch"></div>
</div>

Прописываем общие стили для дочерних элементов.

.img,
.glitch {
  display: block;
  background-image: url('https://images.unsplash.com/photo-1551771685-c367c9127a03?ixid=MXwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=1000&q=80');
  background-repeat: no-repeat;
  background-size: cover;
  width: 564px;
  height: 376px;
}

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

.glitch {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
}
.container {
  position: relative;
}

Отлично. Теперь самое интересное. Мы добавим анимацию при наведении на изображение.

.glitch:hover {
 -webkit-animation-duration:2s;
 animation-duration:2s;
 -webkit-animation-timing-function:linear;
 animation-timing-function:linear;
 -webkit-animation-iteration-count:infinite;
 animation-iteration-count:infinite;
 -webkit-animation-name:glitch-anim;
 animation-name:glitch-anim;
 -webkit-animation-direction:alternate;
 animation-direction:alternate
}

Рассмотрим подробнее каждое свойство:

  • animation-duration - продолжительность анимации, 2 секунды;

  • animation-timing-function - используем линейную функцию, чтобы анимация происходила равномерно;

  • animation-iteration-count - повторяем анимацию бесконечно;

  • animation-name - идентификатор анимации, ее мы опишем чуть ниже;

  • animation-direction - направление анимации, при значении alternate анимация идет с начала до конца, а потом обратно.

Осталась последняя деталь - описать саму анимацию. Для этого воспользуемся правилом @keyframes.

Spoiler
@keyframes glitch-anim {
 0% {
  opacity:1;
  -webkit-transform:translateZ(0);
  transform:translateZ(0);
  -webkit-clip-path:polygon(0 2%,100% 2%,100% 5%,0 5%);
  clip-path:polygon(0 2%,100% 2%,100% 5%,0 5%)
 }
 2% {
  -webkit-clip-path:polygon(0 78%,100% 78%,100% 100%,0 100%);
  clip-path:polygon(0 78%,100% 78%,100% 100%,0 100%);
  -webkit-transform:translate(-5px);
  transform:translate(-5px)
 }
 6% {
  -webkit-clip-path:polygon(0 78%,100% 78%,100% 100%,0 100%);
  clip-path:polygon(0 78%,100% 78%,100% 100%,0 100%);
  -webkit-transform:translate(5px);
  transform:translate(5px)
 }
 8% {
  -webkit-clip-path:polygon(0 78%,100% 78%,100% 100%,0 100%);
  clip-path:polygon(0 78%,100% 78%,100% 100%,0 100%);
  -webkit-transform:translate(-5px);
  transform:translate(-5px)
 }
 9% {
  -webkit-clip-path:polygon(0 78%,100% 78%,100% 100%,0 100%);
  clip-path:polygon(0 78%,100% 78%,100% 100%,0 100%);
  -webkit-transform:translate(0);
  transform:translate(0)
 }
 10% {
  -webkit-clip-path:polygon(0 54%,100% 54%,100% 44%,0 44%);
  clip-path:polygon(0 54%,100% 54%,100% 44%,0 44%);
  -webkit-transform:translate3d(5px,0,0);
  transform:translate3d(5px,0,0)
 }
 13% {
  -webkit-clip-path:polygon(0 54%,100% 54%,100% 44%,0 44%);
  clip-path:polygon(0 54%,100% 54%,100% 44%,0 44%);
  -webkit-transform:translateZ(0);
  transform:translateZ(0)
 }
 13.1% {
  -webkit-clip-path:polygon(0 0,0 0,0 0,0 0);
  clip-path:polygon(0 0,0 0,0 0,0 0);
  -webkit-transform:translate3d(5px,0,0);
  transform:translate3d(5px,0,0)
 }
 15% {
  -webkit-clip-path:polygon(0 60%,100% 60%,100% 40%,0 40%);
  clip-path:polygon(0 60%,100% 60%,100% 40%,0 40%);
  -webkit-transform:translate3d(5px,0,0);
  transform:translate3d(5px,0,0)
 }
 20% {
  -webkit-clip-path:polygon(0 60%,100% 60%,100% 40%,0 40%);
  clip-path:polygon(0 60%,100% 60%,100% 40%,0 40%);
  -webkit-transform:translate3d(-5px,0,0);
  transform:translate3d(-5px,0,0)
 }
 20.1% {
  -webkit-clip-path:polygon(0 0,0 0,0 0,0 0);
  clip-path:polygon(0 0,0 0,0 0,0 0);
  -webkit-transform:translate3d(5px,0,0);
  transform:translate3d(5px,0,0)
 }
 25% {
  -webkit-clip-path:polygon(0 85%,100% 85%,100% 40%,0 40%);
  clip-path:polygon(0 85%,100% 85%,100% 40%,0 40%);
  -webkit-transform:translate3d(5px,0,0);
  transform:translate3d(5px,0,0)
 }
 30% {
  -webkit-clip-path:polygon(0 85%,100% 85%,100% 40%,0 40%);
  clip-path:polygon(0 85%,100% 85%,100% 40%,0 40%);
  -webkit-transform:translate3d(-5px,0,0);
  transform:translate3d(-5px,0,0)
 }
 30.1% {
  -webkit-clip-path:polygon(0 0,0 0,0 0,0 0);
  clip-path:polygon(0 0,0 0,0 0,0 0)
 }
 35% {
  -webkit-clip-path:polygon(0 63%,100% 63%,100% 80%,0 80%);
  clip-path:polygon(0 63%,100% 63%,100% 80%,0 80%);
  -webkit-transform:translate(-5px);
  transform:translate(-5px)
 }
 40% {
  -webkit-clip-path:polygon(0 63%,100% 63%,100% 80%,0 80%);
  clip-path:polygon(0 63%,100% 63%,100% 80%,0 80%);
  -webkit-transform:translate(5px);
  transform:translate(5px)
 }
 45% {
  -webkit-clip-path:polygon(0 63%,100% 63%,100% 80%,0 80%);
  clip-path:polygon(0 63%,100% 63%,100% 80%,0 80%);
  -webkit-transform:translate(-5px);
  transform:translate(-5px)
 }
 50% {
  -webkit-clip-path:polygon(0 63%,100% 63%,100% 80%,0 80%);
  clip-path:polygon(0 63%,100% 63%,100% 80%,0 80%);
  -webkit-transform:translate(0);
  transform:translate(0)
 }
 55% {
  -webkit-clip-path:polygon(0 10%,100% 10%,100% 0,0 0);
  clip-path:polygon(0 10%,100% 10%,100% 0,0 0);
  -webkit-transform:translate3d(5px,0,0);
  transform:translate3d(5px,0,0)
 }
 60% {
  -webkit-clip-path:polygon(0 10%,100% 10%,100% 0,0 0);
  clip-path:polygon(0 10%,100% 10%,100% 0,0 0);
  -webkit-transform:translateZ(0);
  transform:translateZ(0);
  opacity:1
 }
 60.1% {
  -webkit-clip-path:polygon(0 0,0 0,0 0,0 0);
  clip-path:polygon(0 0,0 0,0 0,0 0);
  opacity:1
 }
 to {
  -webkit-clip-path:polygon(0 0,0 0,0 0,0 0);
  clip-path:polygon(0 0,0 0,0 0,0 0);
  opacity:1
 }
}

Пояснения к коду.

Анимация разбита на части в процентном соотношении. В каждой части происходят определенные изменения.

С помощью свойства clip-path вырезается полигон из изображения и к нему применяются различные эффекты. Например, transform: translate(-5px) - сдвигает полигон влево и вверх.

Посмотреть что получилось можно по ссылке.

Теги:
Хабы:
+7
Комментарии 4
Комментарии Комментарии 4

Публикации

Истории

Ближайшие события

Московский туристический хакатон
Дата 23 марта – 7 апреля
Место
Москва Онлайн
Геймтон «DatsEdenSpace» от DatsTeam
Дата 5 – 6 апреля
Время 17:00 – 20:00
Место
Онлайн
PG Bootcamp 2024
Дата 16 апреля
Время 09:30 – 21:00
Место
Минск Онлайн
EvaConf 2024
Дата 16 апреля
Время 11:00 – 16:00
Место
Москва Онлайн