CSS Background Image Flicker Effect

A flicker effect is a mixture of glitch and blinking effects. It is used to represent a glitch or technical loading issue in visual elements. Besides this, it is also useful to display horror content on a webpage. Here, I’m going to share a CSS animation for the background image flicker with a glitch text effect over it.

You can use the flickering image effect in multiple ways. Whether you want to integrate it into the hero section of your webpage or over the image slider, it can be easily used. On the other hand, you can also implement it as a loading error effect. So, let’s get started with coding but before this, have look at the quick video preview:

Video Preview

Besides this, you can also browse the demo page to experience the flickering effect in real time. The background image and text can be customized according to your needs.

The HTML Structure

In HTML, create a div element with a class name "glitch" and place five child divs tags with a class name "glitch-img" inside it. Place your content after the “glitch” div. Use the “content-title” class for your heading and the “content-text” class for your text. Wrap all these elements into a div tag and define its class name "content"

<div class="content">
<div class="glitch">
    <div class="glitch-img"></div>
    <div class="glitch-img"></div>
    <div class="glitch-img"></div>
    <div class="glitch-img"></div>
    <div class="glitch-img"></div>
</div>
<h2 class="content-title">Conjuring</h2>
<p class="content-text">There's a lady in a dirty night gown, that I see in my dreams, she's standin' in front of my mom's bed.</p>
</div>

Place the above HTML code where you want to display the flicker effect. You are not limited to placing only textual content inside the content-text wrapper. You can place any HTML element that will display over the flickering image.

The CSS Styles for Background Image Flicker Effect

In CSS, target the "content" class that is the wrapper element of the background image and content. Define its relative position and display it as flex with justify-content to the center. Set the 100vh min height in order to cover the whole page with the background image.

.content {
	position: relative;
	display: flex;
	justify-content: center;
	align-items: center;
	margin: 0 auto;
	min-height: 100vh;
}

After that, select the "content-title" and "content-text" class and specify the animation name “glitch-anim-text”, duration, timing function, and iteration count as follows:

.content-title,
.content-text {
	animation-name: glitch-anim-text;
	animation-duration: 4s;
	animation-timing-function: linear;
	animation-iteration-count: infinite;
}

Similarly, select these classes individually and define the font family, size, margin, and animation-delay. Here, the important property is the position that you need to set as relative.

.content-title {
	font-size: 12vw;
	margin: 35vh 0 0 0;
	position: relative;
	font-family: 'Playfair Display', serif;
	animation-delay: calc(2s + 4s * 0.2);
}

.content-text {
	font-family: 'IM Fell English', serif;
	position: absolute;
	font-size: 1.5em;
	top: 4em;
	right: 10vw;
	max-width: 500px;
	text-align: right;
	font-weight: 400;
	animation-delay: calc(2s + 4s * 0.25);
}

The "glitch" class specifies the container for the glitch/flicker effect over the background image. Target this class and define its absolute position along with the zero value for the top and the left property. To apply the flicker effect to the full screen, use the 100% width and 100vh height. Keep the overflow hidden in order to avoid overlapping the animation.

/* Glitch styles */
.glitch {
	position: absolute;
	top: 0;
	left: 0;
	width: 100%;
	height: 100vh;
	overflow: hidden;
}

Now, target the "glitch-img" class and define its absolute position along with the top and the left values as 5px and 10px respectively. Use the CSS calc function to calculate the available space for the width and the height. Likewise, set the background image and keep the transparent background color. Moreover, use the CSS 3D transformation in order to enable the browser’s hardware acceleration for smooth animation playback.

.glitch-img {
	position: absolute;
	top: 5px;
	left: 10px;
	width: calc(100% + 10px * 2);
	height: calc(100% + 5px * 2);
	background: url(../img/spooky.jpg) no-repeat 50% 0;
	background-color: transparent;
	background-size: cover;
	transform: translate3d(0,0,0);
	background-blend-mode: none;
}

In the same way, target the "glitch-img" class with CSS nth-child selector and define the following properties as described below:

.glitch-img:nth-child(n+2) {
	opacity: 0;
}

.glitch-img:nth-child(n+2) {
	animation-duration: 4s;
	animation-delay: 2s;
	animation-timing-function: linear;
	animation-iteration-count: infinite;
}
.glitch-img:nth-child(2) {
	background-color: transparent;
	background-blend-mode: none;
	animation-name: glitch-anim-1;
}

.glitch-img:nth-child(3) {
	background-color: transparent;
	background-blend-mode: none;
	animation-name: glitch-anim-2;
}

.glitch-img:nth-child(4) {
	background-color: transparent;
	background-blend-mode: none;
	animation-name: glitch-anim-3;
}

.glitch-img:nth-child(5) {
	background-color: #862a2a;
	background-blend-mode: overlay;
	animation-name: glitch-anim-flash;
}

@media screen and (max-width: 55em) {
	.content {
		flex-direction: column;
		height: auto;
		min-height: 0;
	}
}

Finally, add the following CSS animation keyframes for the flicker effect to your project.

/* Animations */
@keyframes glitch-anim-1 {
	0% { 
		opacity: 1;
		transform: translate3d(10px,0,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 15%, 100% 15%, 100% 15%, 0 15%);
		clip-path: polygon(0 15%, 100% 15%, 100% 15%, 0 15%);
	}
	4% {
		-webkit-clip-path: polygon(0 10%, 100% 10%, 100% 20%, 0 20%);
		clip-path: polygon(0 10%, 100% 10%, 100% 20%, 0 20%);
	}
	6% {
		-webkit-clip-path: polygon(0 1%, 100% 1%, 100% 2%, 0 2%);
		clip-path: polygon(0 1%, 100% 1%, 100% 2%, 0 2%);
	}
	8% {
		-webkit-clip-path: polygon(0 33%, 100% 33%, 100% 33%, 0 33%);
		clip-path: polygon(0 33%, 100% 33%, 100% 33%, 0 33%);
	}
	10% {
		-webkit-clip-path: polygon(0 44%, 100% 44%, 100% 44%, 0 44%);
		clip-path: polygon(0 44%, 100% 44%, 100% 44%, 0 44%);
	}
	12% {
		-webkit-clip-path: polygon(0 50%, 100% 50%, 100% 20%, 0 20%);
		clip-path: polygon(0 50%, 100% 50%, 100% 20%, 0 20%);
	}
	14% {
		-webkit-clip-path: polygon(0 70%, 100% 70%, 100% 70%, 0 70%);
		clip-path: polygon(0 70%, 100% 70%, 100% 70%, 0 70%);
	}
	16% {
		-webkit-clip-path: polygon(0 80%, 100% 80%, 100% 80%, 0 80%);
		clip-path: polygon(0 80%, 100% 80%, 100% 80%, 0 80%);
	}
	18% {
		-webkit-clip-path: polygon(0 50%, 100% 50%, 100% 55%, 0 55%);
		clip-path: polygon(0 50%, 100% 50%, 100% 55%, 0 55%);
	}
	20% {
		-webkit-clip-path: polygon(0 70%, 100% 70%, 100% 80%, 0 80%);
		clip-path: polygon(0 70%, 100% 70%, 100% 80%, 0 80%);
	}
	21.9% {
		opacity: 1;
		transform: translate3d(10px,0,0);
	}
	22%, 100% {
		opacity: 0;
		transform: translate3d(0,0,0);
		-webkit-clip-path: polygon(0 0, 0 0, 0 0, 0 0);
		clip-path: polygon(0 0, 0 0, 0 0, 0 0);
	}
}

@keyframes glitch-anim-2 {
	0% { 
		opacity: 1;
		transform: translate3d(10px,0,0);
		-webkit-clip-path: polygon(0 25%, 100% 25%, 100% 30%, 0 30%);
		clip-path: polygon(0 25%, 100% 25%, 100% 30%, 0 30%);
	}
	3% {
		-webkit-clip-path: polygon(0 3%, 100% 3%, 100% 3%, 0 3%);
		clip-path: polygon(0 3%, 100% 3%, 100% 3%, 0 3%);
	}
	5% {
		-webkit-clip-path: polygon(0 5%, 100% 5%, 100% 20%, 0 20%);
		clip-path: polygon(0 5%, 100% 5%, 100% 20%, 0 20%);
	}
	7% {
		-webkit-clip-path: polygon(0 20%, 100% 20%, 100% 20%, 0 20%);
		clip-path: polygon(0 20%, 100% 20%, 100% 20%, 0 20%);
	}
	9% {
		-webkit-clip-path: polygon(0 40%, 100% 40%, 100% 40%, 0 40%);
		clip-path: polygon(0 40%, 100% 40%, 100% 40%, 0 40%);
	}
	11% {
		-webkit-clip-path: polygon(0 52%, 100% 52%, 100% 59%, 0 59%);
		clip-path: polygon(0 52%, 100% 52%, 100% 59%, 0 59%);
	}
	13% {
		-webkit-clip-path: polygon(0 60%, 100% 60%, 100% 60%, 0 60%);
		clip-path: polygon(0 60%, 100% 60%, 100% 60%, 0 60%);
	}
	15% {
		-webkit-clip-path: polygon(0 75%, 100% 75%, 100% 75%, 0 75%);
		clip-path: polygon(0 75%, 100% 75%, 100% 75%, 0 75%);
	}
	17% {
		-webkit-clip-path: polygon(0 65%, 100% 65%, 100% 40%, 0 40%);
		clip-path: polygon(0 65%, 100% 65%, 100% 40%, 0 40%);
	}
	19% {
		-webkit-clip-path: polygon(0 45%, 100% 45%, 100% 50%, 0 50%);
		clip-path: polygon(0 45%, 100% 45%, 100% 50%, 0 50%);
	}
	20% {
		-webkit-clip-path: polygon(0 14%, 100% 14%, 100% 33%, 0 33%);
		clip-path: polygon(0 14%, 100% 14%, 100% 33%, 0 33%);
	}
	21.9% {
		opacity: 1;
		transform: translate3d(10px,0,0);
	}
	22%, 100% {
		opacity: 0;
		transform: translate3d(0,0,0);
		-webkit-clip-path: polygon(0 0, 0 0, 0 0, 0 0);
		clip-path: polygon(0 0, 0 0, 0 0, 0 0);
	}
}

@keyframes glitch-anim-3 {
	0% { 
		opacity: 1;
		transform: translate3d(0, 5px, 0) scale3d(-1,-1,1);
		-webkit-clip-path: polygon(0 1%, 100% 1%, 100% 3%, 0 3%);
		clip-path: polygon(0 1%, 100% 1%, 100% 3%, 0 3%);
	}
	1.5% {
		-webkit-clip-path: polygon(0 10%, 100% 10%, 100% 9%, 0 9%);
		clip-path: polygon(0 10%, 100% 10%, 100% 9%, 0 9%);
	}
	2% {
		-webkit-clip-path: polygon(0 5%, 100% 5%, 100% 6%, 0 6%);
		clip-path: polygon(0 5%, 100% 5%, 100% 6%, 0 6%);
	}
	2.5% {
		-webkit-clip-path: polygon(0 20%, 100% 20%, 100% 20%, 0 20%);
		clip-path: polygon(0 20%, 100% 20%, 100% 20%, 0 20%);
	}
	3% {
		-webkit-clip-path: polygon(0 10%, 100% 10%, 100% 10%, 0 10%);
		clip-path: polygon(0 10%, 100% 10%, 100% 10%, 0 10%);
	}
	5% {
		-webkit-clip-path: polygon(0 30%, 100% 30%, 100% 25%, 0 25%);
		clip-path: polygon(0 30%, 100% 30%, 100% 25%, 0 25%);
	}
	5.5% {
		-webkit-clip-path: polygon(0 15%, 100% 15%, 100% 16%, 0 16%);
		clip-path: polygon(0 15%, 100% 15%, 100% 16%, 0 16%);
	}
	7% {
		-webkit-clip-path: polygon(0 40%, 100% 40%, 100% 39%, 0 39%);
		clip-path: polygon(0 40%, 100% 40%, 100% 39%, 0 39%);
	}
	8% {
		-webkit-clip-path: polygon(0 20%, 100% 20%, 100% 21%, 0 21%);
		clip-path: polygon(0 20%, 100% 20%, 100% 21%, 0 21%);
	}
	9% {
		-webkit-clip-path: polygon(0 60%, 100% 60%, 100% 55%, 0 55%);
		clip-path: polygon(0 60%, 100% 60%, 100% 55%, 0 55%);
	}
	10.5% {
		-webkit-clip-path: polygon(0 30%, 100% 30%, 100% 31%, 0 31%);
		clip-path: polygon(0 30%, 100% 30%, 100% 31%, 0 31%);
	}
	11% {
		-webkit-clip-path: polygon(0 70%, 100% 70%, 100% 69%, 0 69%);
		clip-path: polygon(0 70%, 100% 70%, 100% 69%, 0 69%);
	}
	13% {
		-webkit-clip-path: polygon(0 40%, 100% 40%, 100% 41%, 0 41%);
		clip-path: polygon(0 40%, 100% 40%, 100% 41%, 0 41%);
	}
	14% {
		-webkit-clip-path: polygon(0 80%, 100% 80%, 100% 75%, 0 75%);
		clip-path: polygon(0 80%, 100% 80%, 100% 75%, 0 75%);
	}
	14.5% {
		-webkit-clip-path: polygon(0 50%, 100% 50%, 100% 51%, 0 51%);
		clip-path: polygon(0 50%, 100% 50%, 100% 51%, 0 51%);
	}
	15% {
		-webkit-clip-path: polygon(0 90%, 100% 90%, 100% 90%, 0 90%);
		clip-path: polygon(0 90%, 100% 90%, 100% 90%, 0 90%);
	}
	16% {
		-webkit-clip-path: polygon(0 60%, 100% 60%, 100% 60%, 0 60%);
		clip-path: polygon(0 60%, 100% 60%, 100% 60%, 0 60%);
	}
	18% {
		-webkit-clip-path: polygon(0 100%, 100% 100%, 100% 99%, 0 99%);
		clip-path: polygon(0 100%, 100% 100%, 100% 99%, 0 99%);
	}
	20% {
		-webkit-clip-path: polygon(0 70%, 100% 70%, 100% 71%, 0 71%);
		clip-path: polygon(0 70%, 100% 70%, 100% 71%, 0 71%);
	}
	21.9% {
		opacity: 1;
		transform: translate3d(0, 5px, 0) scale3d(-1,-1,1);
	}
	22%, 100% {
		opacity: 0;
		transform: translate3d(0,0,0);
		-webkit-clip-path: polygon(0 0, 0 0, 0 0, 0 0);
		clip-path: polygon(0 0, 0 0, 0 0, 0 0);
	}
}

@keyframes glitch-anim-text {
	0% { 
		transform: translate3d(10px,0,0) scale3d(-1,-1,1);
		-webkit-clip-path: polygon(0 20%, 100% 20%, 100% 21%, 0 21%);
		clip-path: polygon(0 20%, 100% 20%, 100% 21%, 0 21%);
	}
	2% {
		-webkit-clip-path: polygon(0 33%, 100% 33%, 100% 33%, 0 33%);
		clip-path: polygon(0 33%, 100% 33%, 100% 33%, 0 33%);
	}
	4% {
		-webkit-clip-path: polygon(0 44%, 100% 44%, 100% 44%, 0 44%);
		clip-path: polygon(0 44%, 100% 44%, 100% 44%, 0 44%);
	}
	5% {
		-webkit-clip-path: polygon(0 50%, 100% 50%, 100% 20%, 0 20%);
		clip-path: polygon(0 50%, 100% 50%, 100% 20%, 0 20%);
	}
	6% {
		-webkit-clip-path: polygon(0 70%, 100% 70%, 100% 70%, 0 70%);
		clip-path: polygon(0 70%, 100% 70%, 100% 70%, 0 70%);
	}
	7% {
		-webkit-clip-path: polygon(0 80%, 100% 80%, 100% 80%, 0 80%);
		clip-path: polygon(0 80%, 100% 80%, 100% 80%, 0 80%);
	}
	8% {
		-webkit-clip-path: polygon(0 50%, 100% 50%, 100% 55%, 0 55%);
		clip-path: polygon(0 50%, 100% 50%, 100% 55%, 0 55%);
	}
	9% {
		-webkit-clip-path: polygon(0 70%, 100% 70%, 100% 80%, 0 80%);
		clip-path: polygon(0 70%, 100% 70%, 100% 80%, 0 80%);
	}
	9.9% {
		transform: translate3d(10px,0,0) scale3d(-1,-1,1);
	}
	10%, 100% {
		transform: translate3d(0,0,0) scale3d(1,1,1);
		-webkit-clip-path: polygon(0 0, 100% 0, 100% 100%, 0% 100%);
		clip-path: polygon(0 0, 100% 0, 100% 100%, 0% 100%);
	}
}

/* Flash */
@keyframes glitch-anim-flash {
	0%, 5% { 
		opacity: 0.2; 
		transform: translate3d(10px, 5px, 0);
	}
	5.5%, 100% {
		opacity: 0;
		transform: translate3d(0, 0, 0);
	}
}

That’s all! I hope, you have successfully created a CSS background image flicker effect. If you have any suggestions or questions, feel free to comment below. Happy coding 😀

You Might Be Interested In: