GLITCH: Эффект неисправного монитора для текста, картинок и SVG
Эффект Glitch Лукаса Беббера выглядит очень круто — как будто вы смотрите на текст на старом мониторе, который слишком часто роняли на пол и у него «плавает» вертикальная синхронизация и сведение.
Реализация этого эффекта на CSS выглядит вполне убедительно. Мне пришлось немного поломать голову, чтобы выяснить, как он работает, и теперь я хочу объяснить это вам. Кроме того, я воспроизвёл этот эффект не только для текста, но и для растровых изображений и SVG, а так же написал несколько примесей Sass, чтобы облегчить работу с ним.
Три копии текста
HTML для этого примера выглядит просто:
<br /> <div class="glitch" data-text="GLITCH">GLITCH</div> <p>
С помощью псевдоэлементов создаются две дополнительные копии основного элемента, которыми можно управлять индивидуально:
.glitch {<br /> position: relative;<br /> }<br /> .glitch::before,<br /> .glitch::after {<br /> content: attr(data-text);<br /> position: absolute;<br /> top: 0;<br /> left: 0;<br /> width: 100%;<br /> height: 100%;<br /> }
Все три копии текста расположены друг над другом:
Изменяем копии
Каждая из дополнительных копий идентична оригиналу за исключением того, что:
они смещены влево или вправо;
У них есть цветной ореол, созданный с помощью text-shadow.
Именно смещение и ореол служат основой для эффекта неисправного монитора.
.glitch::before {<br /> /* ... всё, что нужно, чтобы сделать слой идентичным оригиналу */</p> <p> /* отличия от оригинала */<br /> left: 2px;<br /> text-shadow: -1px 0 red;</p> <p> /* Важно: непрозрачный фон закрывает предыдущий слой */<br /> background: black;<br /> }<br /> .glitch::after {<br /> /* ... всё, что нужно, чтобы сделать слой идентичным оригиналу */</p> <p> /* отличия от оригинала */<br /> left: -2px;<br /> text-shadow: -1px 0 blue;</p> <p> /* Важно: непрозрачный фон закрывает предыдущий слой */<br /> background: black;<br /> }
Теперь наши три копии выглядят так:
Обрезаем копии
Пока что нам видна только самая верхняя из трёх копий. Скорее всего, это версия ::after, если только вы не меняли z-index. Но это не важно, так как мы будем попеременно показывать части всех трёх копий с помощью свойства clip. В данный момент это свойство уже считается устаревшим, его должно заменить clip-path, но на момент написания статьи именно свойство clip работало лучше. Конечно, со временем это изменится, так что нужно иногда поглядывать на ситуацию. В случае чего, их легко будет поменять, например, с помощью Autoprefixer.
У clip довольно странный синтаксис. Требуются четыре значения, логично было бы предположить, что это координаты верхнего левого угла и длина с шириной, или координаты верхнего левого и нижнего правого углов, но вместо этого числа означают отступы, как в свойствах margin или padding (top/right/bottom/left).
.glitch::before {<br /> clip: rect(44px, 450px, 56px, 0);<br /> /*<br /> Получился прямоугольник с верхним левым углом 0, 44px<br /> и нижним правым 450px, 56px<br /> */<br /> }
Вот как может выглядеть результат обрезки, для наглядности фон сделан непрозрачным и слои смещены друг относительно друга:
Анимируем обрезку
Для свойства clip можно использовать анимации CSS, меняя положение обрезающего прямоугольника. Вот пример такой анимации:
@keyframes glitch-anim {<br /> 0% {<br /> clip: rect(70px, 450px, 76px, 0);<br /> }<br /> 20% {<br /> clip: rect(29px, 450px, 16px, 0);<br /> }<br /> 40% {<br /> clip: rect(76px, 450px, 3px, 0);<br /> }<br /> 60% {<br /> clip: rect(42px, 450px, 78px, 0);<br /> }<br /> 80% {<br /> clip: rect(15px, 450px, 13px, 0);<br /> }<br /> 100% {<br /> clip: rect(53px, 450px, 5px, 0);<br /> }<br /> }
Обратите внимание, что левый и правый край остаются неизменными, меняются только верхний и нижний край. И эти значения выбраны совершенно произвольно. С помощью Sass вполне можно генерировать их случайным образом:
@keyframes glitch-anim {<br /> $steps: 10;<br /> @for $i from 0 through $steps {<br /> #{percentage($i*(1/$steps))} {<br /> clip: rect(random(100)+px, 9999px, random(100)+px, 0);<br /> }<br /> }<br /> }
Так как нам понадобятся два набора случайных обрезающих прямоугольников, надо будет сделать два набора ключевых кадров и применить их к двум копиям:
.glitch::before {<br /> ...</p> <p> animation: glitch-anim-1 2s infinite linear alternate-reverse;<br /> }</p> <p>.glitch::after {<br /> ...</p> <p> animation: glitch-anim-2 2s infinite linear alternate-reverse;<br /> }
В этом месте мы можем отрегулировать скорость анимации зациклить её. Эффект готов:
Примеси Sass
Я подумал, что хорошо бы добавить этому эффекту возможность удобного повторного использования. Например, написать примесь Sass с параметрами, с помощью которых можно контролировать эффект:
.example-one {<br /> font-size: 100px;<br /> @include textGlitch("example-one", 17, white, black, red, blue, 450, 115);<br /> }
Вот что у меня получилось:
/*<br /> (TEXT) PARAMS<br /> =================<br /> 1. Namespace<br /> 2. Intensity<br /> 3. Text color<br /> 4. Background color (flat)<br /> 5. Highlight #1 color<br /> 6. Highlight #2 color<br /> 7. Width (px)<br /> 8. Height (px)<br /> */</p> <p>@mixin textGlitch($name, $intensity, $textColor, $background, $highlightColor1, $highlightColor2, $width, $height) {</p> <p> color: $textColor;<br /> position: relative;<br /> $steps: $intensity;</p> <p> // Ensure the @keyframes are generated at the root level<br /> @at-root {<br /> // We need two different ones<br /> @for $i from 1 through 2 {<br /> @keyframes #{$name}-anim-#{$i} {<br /> @for $i from 0 through $steps {<br /> #{percentage($i*(1/$steps))} {<br /> clip: rect(<br /> random($height)+px,<br /> $width+px,<br /> random($height)+px,<br /> 0<br /> );<br /> }<br /> }<br /> }<br /> }<br /> }<br /> &:before,<br /> &:after {<br /> content: attr(data-text);<br /> position: absolute;<br /> top: 0;<br /> left: 0;<br /> width: 100%;<br /> background: $background;<br /> clip: rect(0, 0, 0, 0);<br /> }<br /> &:after {<br /> left: 2px;<br /> text-shadow: -1px 0 $highlightColor1;<br /> animation: #{$name}-anim-1 2s infinite linear alternate-reverse;<br /> }<br /> &:before {<br /> left: -2px;<br /> text-shadow: 2px 0 $highlightColor2;<br /> animation: #{$name}-anim-2 3s infinite linear alternate-reverse;<br /> }</p> <p>}
Конечно, можно придумать ещё миллион способов, как реализовать эту примесь — всё зависит от того, какие параметры вы хотите настраивать, какая у вас разметка HTML и т.д.
Я также написал ещё две примеси, одну для растровых изображений, вторую — для SVG. Они отличаются деталями реализации — там не используются псевдоэлементы, смещение и цветной ореол тоже делаются по-другому и т.д. Вот все три примеси в одном файле. А вот так выглядит их работа:
Css Дизайнер (designer)