Эффект неисправного монитора для текста, картинок и SVG

в 11:07, , рубрики: CLIP, css, sass, Веб-разработка, эффект неисправного монитора

Эффект Glitch Лукаса Беббера выглядит очень круто — как будто вы смотрите на текст на старом мониторе, который слишком часто роняли на пол и у него «плавает» вертикальная синхронизация и сведение.

Реализация этого эффекта на CSS выглядит вполне убедительно. Мне пришлось немного поломать голову, чтобы выяснить, как он работает, и теперь я хочу объяснить это вам. Кроме того, я воспроизвёл этот эффект не только для текста, но и для растровых изображений и SVG, а так же написал несколько примесей Sass, чтобы облегчить работу с ним.

Эффект неисправного монитора для текста, картинок и SVG

Три копии текста

HTML для этого примера выглядит просто:

<div class="glitch" data-text="GLITCH">GLITCH</div>

С помощью псевдоэлементов создаются две дополнительные копии основного элемента, которыми можно управлять индивидуально:

.glitch {
  position: relative;
}
.glitch::before,
.glitch::after {
  content: attr(data-text);
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
}

Все три копии текста расположены друг над другом:

image

Изменяем копии

Каждая из дополнительных копий идентична оригиналу за исключением того, что:

  • они смещены влево или вправо;
  • У них есть цветной ореол, созданный с помощью text-shadow.

Именно смещение и ореол служат основой для эффекта неисправного монитора.

.glitch::before {
  /* ... всё, что нужно, чтобы сделать слой идентичным оригиналу */

  /* отличия от оригинала */
  left: 2px;
  text-shadow: -1px 0 red;
  
  /* Важно: непрозрачный фон закрывает предыдущий слой */
  background: black;
}
.glitch::after {
  /* ... всё, что нужно, чтобы сделать слой идентичным оригиналу */

  /* отличия от оригинала */
  left: -2px;
  text-shadow: -1px 0 blue;
  
  /* Важно: непрозрачный фон закрывает предыдущий слой */
  background: black;
}

Теперь наши три копии выглядят так:

image

Обрезаем копии

Пока что нам видна только самая верхняя из трёх копий. Скорее всего, это версия ::after, если только вы не меняли z-index. Но это не важно, так как мы будем попеременно показывать части всех трёх копий с помощью свойства clip. В данный момент это свойство уже считается устаревшим, его должно заменить clip-path, но на момент написания статьи именно свойство clip работало лучше. Конечно, со временем это изменится, так что нужно иногда поглядывать на ситуацию. В случае чего, их легко будет поменять, например, с помощью Autoprefixer.

У clip довольно странный синтаксис. Требуются четыре значения, логично было бы предположить, что это координаты верхнего левого угла и длина с шириной, или координаты верхнего левого и нижнего правого углов, но вместо этого числа означают отступы, как в свойствах margin или padding (top/right/bottom/left).

.glitch::before {
  clip: rect(44px, 450px, 56px, 0);
  /*
    Получился прямоугольник с верхним левым углом 0, 44px
    и нижним правым 450px, 56px
  */
}

Вот как может выглядеть результат обрезки, для наглядности фон сделан непрозрачным и слои смещены друг относительно друга:

image

Анимируем обрезку

Для свойства clip можно использовать анимации CSS, меняя положение обрезающего прямоугольника. Вот пример такой анимации:

@keyframes glitch-anim {
  0% {
    clip: rect(70px, 450px, 76px, 0);
  }
  20% {
    clip: rect(29px, 450px, 16px, 0);
  }
  40% {
    clip: rect(76px, 450px, 3px, 0);
  }
  60% {
    clip: rect(42px, 450px, 78px, 0);
  }
  80% {
    clip: rect(15px, 450px, 13px, 0);
  }
  100% {
    clip: rect(53px, 450px, 5px, 0);
  }
}

Обратите внимание, что левый и правый край остаются неизменными, меняются только верхний и нижний край. И эти значения выбраны совершенно произвольно. С помощью Sass вполне можно генерировать их случайным образом:

@keyframes glitch-anim {
  $steps: 10;
  @for $i from 0 through $steps {
    #{percentage($i*(1/$steps))} {
      clip: rect(random(100)+px, 9999px, random(100)+px, 0);
    }
  }
}

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

.glitch::before {
  ...

  animation: glitch-anim-1 2s infinite linear alternate-reverse;
}

.glitch::after {
  ...

  animation: glitch-anim-2 2s infinite linear alternate-reverse;
}

В этом месте мы можем отрегулировать скорость анимации зациклить её. Эффект готов:

Эффект неисправного монитора для текста, картинок и SVG

Примеси Sass

Я подумал, что хорошо бы добавить этому эффекту возможность удобного повторного использования. Например, написать примесь Sass с параметрами, с помощью которых можно контролировать эффект:

.example-one {
  font-size: 100px;
  @include textGlitch("example-one", 17, white, black, red, blue, 450, 115);
}

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

/*
  (TEXT) PARAMS
  =================
  1. Namespace
  2. Intensity
  3. Text color
  4. Background color (flat)
  5. Highlight #1 color
  6. Highlight #2 color
  7. Width (px)
  8. Height (px)
*/

@mixin textGlitch($name, $intensity, $textColor, $background, $highlightColor1, $highlightColor2, $width, $height) {
  
  color: $textColor;
  position: relative;
  $steps: $intensity;
  
  // Ensure the @keyframes are generated at the root level
  @at-root {
    // We need two different ones
    @for $i from 1 through 2 {
      @keyframes #{$name}-anim-#{$i} {
        @for $i from 0 through $steps {
          #{percentage($i*(1/$steps))} {
            clip: rect(
              random($height)+px,
              $width+px,
              random($height)+px,
              0
            );
          }
        }
      }
    }
  }
  &:before,
  &:after {
    content: attr(data-text);
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    background: $background;
    clip: rect(0, 0, 0, 0); 
  }
  &:after {
    left: 2px;
    text-shadow: -1px 0 $highlightColor1;
    animation: #{$name}-anim-1 2s infinite linear alternate-reverse;
  }
  &:before {
    left: -2px;
    text-shadow: 2px 0 $highlightColor2; 
    animation: #{$name}-anim-2 3s infinite linear alternate-reverse;
  }
  
}

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

Я также написал ещё две примеси, одну для растровых изображений, вторую — для SVG. Они отличаются деталями реализации — там не используются псевдоэлементы, смещение и цветной ореол тоже делаются по-другому и т.д. Вот все три примеси в одном файле. А вот так выглядит их работа:

Автор: ilya42

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js