How to create glitch text and image effects in CSS

In this tutorial, we'll show you how to create a glitch text effect. Special effects and animations can help websites stand out, creating an immediate impact on the user before they've had a chance to get into reading the main content. If your homepage needs to wow visitors, you can create tons of different effects using just CSS. 

Our process for creating glitch text here is actually pretty similar to working with animation software. We'll place keyframes at specific points, and use these to control the action. The difference with the keyframes in CSS is that they are written as percentages for the timeline of animation in the code. This isn't anywhere near as daunting as it sounds – once you try it, it's relatively straightforward to achieve good results. 

There will be a small amount of JavaScript used in the tutorial – to remove the loading screen once the images load onto the page – but the main focus here is on CSS animation. We'll also use CSS Grid to position elements on the screen. 

01. Get set up

To get started, open the start folder from the project files inside your code editor. Open the index.html page, which contains just a barebones skeleton HTML page. In the head section, the fonts need linking up so that the design displays correctly. Add the style link for the fonts.

<link href="https://fonts.googleapis.com/css?family=IM+Fell+English|Playfair+Display:900"rel="stylesheet">

The basic layout in CSS has been started in the site.css file, but all of the important parts relating to the glitch effect are going to be added later. In the head section of the document link up the CSS so that the basic design of the page is in place.

<link rel="stylesheet" type="text/css" 
href="css/site.css" />

03. Set up a loading screen

Black home screen with brand icon

This screen will display while the page loads

Now move to the body section of the page. This contains all the visible elements of the page that show up in the browser. Here add in a div that will hold the 'preloader screen' until everything on the page has loaded. This will display a logo in the centre of the page.

<div id="loader" class="loading">
       <div class="loading-logo"><img src="img/logo.svg" class="logo"></div>
   </div>

04. Add a header bar

Black home screen with title and short description displayed

The basic elements of the design, before the glitch text effect is added

Along the top of the screen will be a small header containing an SVG logo for the site on the left with a text heading. Then on the right-hand side of the screen, an inline menu will be in place for easy navigation. The structure of the code here adds those elements onto the page.

<div class="contentFixed">
       <header class="header">
           <h1 class="headerTitle"><img 
src="img/logo.svg" class="logo"> HackerCon</h1>
       </header>
       <nav class="menu" id="siteNav">
           <ul>
               <li><a href="index.html">Home</a></li>
               <li><a href="news.html">News</a></li>
               <li><a href="contact.html">Contact</a></li>
               <li><a href="about.html">About</a></li>
           </ul>
       </nav>
   </div>

05. Add images

Now the section that follows contains several versions of the same image in the glitchit class. What this will do is have different parts of these images turned on and off at different times in order to give a glitch effect. Following this is the text that will sit over the top of the images.

<div class="content">
       <div class="glitch">
            <div class="glitchit"></div>
            <div class="glitchit"></div>
            <div class="glitchit"></div>
            <div class="glitchit"></div>
            <div class="glitchit"></div>
       </div>
       <div class="contentSection">
       <h2 class="contentTitle">Hacker<span>Con</span></h2>
          <p class="contentText">Add a description</p>
           </div>
       </div>

06. Trigger the glitch text effect

At the end of the body content the JavaScript tags are placed. All this does is check that the page has loaded and then removes the loading screen, which in turn triggers the glitch effect animation to start by adding a class to the body to affect the relevant glitch sections.

<script>
       var loader = document.getElementById('loader');
       window.addEventListener("load", 
function(event) {
           loader.classList.
remove('loading');
           loader.classList.add('loaded');
           document.body.classList.
add('imgloaded');
       });
</script>

07. Set up CSS Variables

Save the page now and move over to the site.css file in the CSS folder. There is already code here, but right above any other code add in the variables shown below. These CSS Variables will hold colours and sizes that will be used later on in the design.

body {
   --color-text: #fff;
   --color-bg: #000;
   --color-link: #555;
   --color-link-hover: #98fadf;
   --color-info: #f7cfb9;
   --glitch-width: 100vw;
   --glitch-height: 100vh;
   --gap-horizontal: 10px;
   --gap-vertical: 5px;
   --time-anim: 4s;
   --delay-anim: 2s;

08. Experiment with Variable settings

As you will see, these Variables are assigned to the body tag so they can be used by any tag on the page inside the body, which is essentially all the visible page. Here the transparency and blending modes are set up for the different images. There are five images and you can experiment with these settings to get different results.

   --blend-mode-1: none;
   --blend-mode-2: overlay;
   --blend-mode-3: none;
   --blend-mode-4: none;
   --blend-mode-5: overlay;
   --blend-color-1: transparent;
   --blend-color-2: #7d948e;
   --blend-color-3: transparent;
   --blend-color-4: transparent;
   --blend-color-5: #af4949;
}

09. Fill the screen with images

To keep the code neatly together, scroll down to the comment that mark steps 9 to 13 in the CSS file, adding in this code. Here the glitch code positions the div containing all images to fill the full screen and be positioned absolutely in the top left of the screen. Note it gets its width and height from the CSS Variables.

.glitch 
{
   position: absolute;
   top: 0;
   left: 0;
   width: var(--glitch-width);
   height: var(--glitch-height);
   overflow: hidden;
}

10. Adjust image positioning

Homepage with fullscreen photograph added

The glitch effect uses repositioned copies of the same image

As the glitch effect is made up out of copies of the same image, this code positions each div in the page and makes it slightly larger than the screen. It positions it off the top and left to account for it being bigger, and the image is then placed in the background to fill the image.

.glitchit {
   position: absolute;
   top: calc(-1 * var(--gap-vertical));
   left: calc(-1 * var(--gap-horizontal));
   width: calc(100% + var(--gap-horizontal) * 
2);
   height: calc(100% + var(--gap-vertical) * 
2);
   background: url(../img/main.jpg) no-repeat 
50% 0;
   background-color: var(--blend-color-1);
   background-size: cover;
   transform: translate3d(0, 0, 0);
   background-blend-mode: var(--blend-
mode-1);
}

11. Select images

The code here selects every image except the first image. This is because the first image stays on the page, while the others turn on and off over the top with the keyframe animation. These top images are hidden until they are needed with the opacity set to zero.

.glitchit:nth-child(n+2) {
   opacity: 0;
}
.imgloaded .glitchit:nth-child(n+2) {
   animation-duration: var(--time-anim);
   animation-delay: var(--delay-anim);
   animation-timing-function: linear;
   animation-iteration-count: infinite;
}

12. Adjust images two and three

The second and third image are set to animate in this code. They are given the respective blend and colour modes so that they show up differently. The biggest difference here is that they are given different keyframe animations to follow to mix.

up the effects.
.imgloaded .glitchit:nth-child(2) {
   background-color: var(--blend-color-2);
   background-blend-mode: var(--blend-
mode-2);
   animation-name: glitch-1;
}
.imgloaded .glitchit:nth-child(3) {
   background-color: var(--blend-color-3);
   background-blend-mode: var(--blend-
mode-3);
   animation-name: glitch-2;
}

13. Adjust images four and five

This time the next two images are set up quite close to the others, but again this time there is different blending modes and animations for these images to show up. The keyframes have not yet been created for some of these animations and that will come next.

.imgloaded .glitchit:nth-child(4) {
   background-color: var(--blend-color-4);
   background-blend-mode: var(--blend-
mode-4);
   animation-name: glitch-3;
}
.imgloaded .glitchit:nth-child(5) {
   background-color: var(--blend-color-5);
   background-blend-mode: var(--blend-
mode-5);
   animation-name: glitch-flash;
}

14. Add the first set of keyframes

The keyframes work by grabbing different sections of the image and clipping it down so only that will be visible. The opacity is turned on and off at different times so that parts of the image are visible at different times to the other animations and thus creates the glitch effect. The image is moved slightly on the x-axis.

@keyframes glitch-1 {
   0% {
       opacity: 1;
       transform: translate3d(var(--gap-
horizontal), 0, 0);
       clip-path: polygon(0 2%, 100% 2%, 
100% 5%, 0 5%);
   } 2% {
       clip-path: polygon(0 15%, 100% 15%, 
100% 15%, 0 15%);
   }

15. Use the clip-path

The clip path is taking a rectangle so the first two numbers are top left, then top right. This is followed by bottom right and bottom left. By moving these numbers different parts of the image become visible at different points.

4% {
       clip-path: polygon(0 10%, 100% 10%, 
100% 20%, 0 20%);
   } 6% {
       clip-path: polygon(0 1%, 100% 1%, 
100% 2%, 0 2%);
   } 8% {
       clip-path: polygon(0 33%, 100% 33%, 1
00% 33%, 0 33%);
   } 10% {
       clip-path: polygon(0 44%, 100% 44%, 
100% 44%, 0 44%);
   }

16. Speed up the movement

By moving the clip path so quickly over a number of the keyframes, the effect builds up and different parts of the image appear to flash around in an erratic fashion. Add that more layers of images are also doing this and the effect works very well at what it does.

12% {
       clip-path: polygon(0 50%, 100% 50%, 
100% 20%, 0 20%);
   } 14% {
       clip-path: polygon(0 70%, 100% 70%, 
100% 70%, 0 70%);
   }16% {
       clip-path: polygon(0 80%, 100% 80%, 
100% 80%, 0 80%);
   }18% {
       clip-path: polygon(0 50%, 100% 50%, 
100% 55%, 0 55%);
   }20% {
       clip-path: polygon(0 70%, 100% 70%, 
100% 80%, 0 80%);
   } 

17. Finish up the image glitches

After 22% the image is turned off until the animation plays back again. This completes the glitch-1 effect with glitch-2 and glitch-3 already being supplied in the code. The next section will glitch the text that is over the top of the image as well.

21.9% {
       opacity: 1;
       transform: translate3d(var(--gap-
horizontal), 0, 0);
   } 22%, 100% {
       opacity: 0;
       transform: translate3d(0, 0, 0);
       clip-path: polygon(0 0, 0 0, 0 0, 0 
0);
   }
} 

18. How to create glitch text

Text cropped to show glitch effect in progress on homepage

The text is only clipped briefly, to ensure it's still readable

This code works extremely similarly to the previous code except that it flips the text upside down and then clips it, to give a jumping effect that is moved dramatically. Following that the clip path is revealing only smaller sections, with the fast movement through the keyframes.

@keyframes glitch-text {
   0% {
       transform: translate3d(calc(-1 * 
var(--gap-horizontal)), 0, 0) scale3d(-1, -1, 
1);
       clip-path: polygon(0 20%, 100% 20%, 
100% 21%, 0 21%);
   } 2% {
       clip-path: polygon(0 33%, 100% 33%, 
100% 33%, 0 33%);
   } 4% {
       clip-path: polygon(0 44%, 100% 44%, 
100% 44%, 0 44%);
   } 

19. More clipping 

The effect continues in this section of code by rapidly changing the shape of the clipping path. The clip-path also comes with the -webkit- prefix but for brevity this has not been shown in any of the code here. At time of writing, Clip Path is currently not supported in IE, Edge or Opera Mini, but is in all other browsers. 

5% {
       clip-path: polygon(0 50%, 100% 50%, 
100% 20%, 0 20%);
   } 6% {
       clip-path: polygon(0 70%, 100% 70%, 
100% 70%, 0 70%);
   } 7% {
       clip-path: polygon(0 80%, 100% 80%, 
100% 80%, 0 80%);
   }  8% {
       clip-path: polygon(0 50%, 100% 50%, 
100% 55%, 0 55%);
   } 

20. Flip the text back

In the final text glitch animation the text flips back to its original position and waits for the keyframes to come around again. As you can see all of the animation takes place in 10 per cent while it stays dormant for 90 per cent of the time, giving the text the right amount of distress and allowing it to be readable.

9% {
       clip-path: polygon(0 70%, 100% 70%, 
100% 80%, 0 80%);
   } 9.9% {
       transform: translate3d(calc(-1 * 
var(--gap-horizontal)), 0, 0) scale3d(-1, -1, 
1);
   } 10%, 100% {
       transform: translate3d(0, 0, 0) 
scale3d(1, 1, 1);
       clip-path: polygon(0 0, 100% 0, 100% 
100%, 0% 100%);
   }
} 

21. Create a quick flash

Homepage with glitch effect in progress

The glitch effect runs every few seconds to give a distressed look

The final step is that one image is given the glitch-flash animation, and this series of keyframes just place the image on the screen with a 20 per cent opacity for a short period just to give an offset of the original. Save the CSS file now and the effect should start playing once the content loads in the browser.

@keyframes glitch-flash {
   0%, 5% {
       opacity: 0.2;
       transform: translate3d(var(--gap-
horizontal), var(--gap-vertical), 0);
   } 5.5%, 100% {
       opacity: 0;
       transform: translate3d(0, 0, 0);
} } 

This article was originally published in creative web design magazine Web Designer. Buy issue 281 or subscribe.

Read more: