📜 ⬆️ ⬇️

The effect of a faulty monitor for text, images and SVG

The effect of Lukas Bebber's Glitch looks very cool - as if you are looking at text on an old monitor that has been dropped too often on the floor and it has vertical sync and mixing.

The implementation of this effect on CSS looks quite convincing. I had to break my head a little to figure out how it works, and now I want to explain it to you. In addition, I reproduced this effect not only for text, but also for raster images and SVG, and also wrote a few Sass impurities to facilitate working with it.



Three copies of text


The HTML for this example looks simple:
')
<div class="glitch" data-text="GLITCH">GLITCH</div> 

With the help of pseudo-elements, two additional copies of the main element are created that can be controlled individually:

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

All three copies of the text are located one above the other:

image

Modifying copies


Each additional copy is identical to the original, except that:


This offset and halo are the basis for the effect of a faulty monitor.

 .glitch::before { /* ... ,  ,      */ /*    */ left: 2px; text-shadow: -1px 0 red; /* :      */ background: black; } .glitch::after { /* ... ,  ,      */ /*    */ left: -2px; text-shadow: -1px 0 blue; /* :      */ background: black; } 

Now our three copies look like this:

image

Crop copies


So far, we only see the topmost of the three copies. Most likely, this is the version ::after , unless you changed the z-index . But this is not important, since we will alternately show parts of all three copies using the clip property. At the moment, this property is already considered obsolete, it should be replaced by the clip-path , but at the time of writing this article, the clip property worked better. Of course, this will change over time, so sometimes you have to look at the situation. In which case, they will be easy to change, for example, using Autoprefixer .

The clip rather strange syntax. It requires four values, it would be logical to assume that these are the coordinates of the upper left corner and the length with the width, or the coordinates of the upper left and lower right corners, but instead the numbers mean padding, as in the properties margin or padding ( top/right/bottom/left ).

 .glitch::before { clip: rect(44px, 450px, 56px, 0); /*       0, 44px    450px, 56px */ } 

Here's how the result of the cropping might look like, for clarity, the background is made opaque and the layers are offset from each other:

image

Animate trimming


For the clip property, you can use CSS animations by changing the position of the cropping rectangle. Here is an example of such an animation:

 @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); } } 

Please note that the left and right edges remain unchanged, only the upper and lower edges change. And these values ​​are chosen completely arbitrarily. Using Sass, it is quite possible to generate them at random:

 @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); } } } 

Since we will need two sets of random cropping rectangles, we will need to make two sets of key frames and apply them to two copies:

 .glitch::before { ... animation: glitch-anim-1 2s infinite linear alternate-reverse; } .glitch::after { ... animation: glitch-anim-2 2s infinite linear alternate-reverse; } 

In this place we can adjust the speed of the animation to loop it. The effect is ready:



Impurities Sass


I thought it would be a good idea to add reusability to this effect. For example, write a Sass admixture with parameters that can be used to control the effect:

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

Here's what I got:

 /* (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; } } 

Of course, you can come up with a million more ways to implement this impurity - it all depends on what parameters you want to customize, what HTML markup you have, etc.

I also wrote two more impurities, one for raster images, the other for SVG. They differ in implementation details — pseudo-elements are not used there, displacement and color halo are also made differently, and so on. Here are all three impurities in one file . And this is how their work looks like:



Source: https://habr.com/ru/post/236263/


All Articles