I first noticed animated borders on deno.com a while back. Their feature cards had these smooth, glowing green lines moving around the edges. I thought to myself,
“Wow… that must be some incredibly complex Javascript magic.”
I promised myself that one day I’d learn how to build something just as cool.
Turns out… you can create animated borders using only HTML and CSS and it’s way easier than I expected.
Before we embark on this will be our final product.
Starting Up
Lets begin with some basic HTML.
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Animated Borders</title>
</head>
<body>
<div class="card"></div>
</body>
</html>
Create a CSS file, link it to our HTML and some basic styling to the body & the box:
<link rel="stylesheet" href="index.css" >
body {
background: oklch(0.1743 0.0227 283.7998);
margin: 0;
padding: 0;
height: 100svh;
display: flex;
justify-content: center;
align-items: center;
}
.card {
height: 400px;
aspect-ratio: 1/1;
background: oklch(0.2284 0.0384 282.9324);
border-radius: 12px;
}
CSS After & Before Pseudo Elements
MDN docs by mozilla says the following about CSS pseudo elements.
A CSS pseudo-element is a keyword added to a selector that lets you style a specific part of the selected element(s).
So from my understanding pseudo elements help you to style specific elements without additional HTML.
We'll create a new visual layer behind the card using ::before
.card::before {
content: "";
height: 100%;
width: 100%;
background: conic-gradient(
from 0deg at center,
red,
orange,
blue,
purple,
red
);
position: absolute;
z-index: -2;
border-radius: inherit;
padding: 2px;
}
.card {
/* add the following styles to the card */
position: relative;
display: flex;
justify-content: center;
align-items: center;
}
The padding on the ::before pseudo element serves as our border, you can make it as thick as you wish (or as thin). You will now see a colourful border around the card.
Now to make the "border" animated we now employ the sibling to ::before pseudo element, the ::after pseudo element.
The latter works exactly as the former element, so just add it to the existing ::before element and separate them with a comma.
We will use it to give our 'border' a softer glow.
.card::before, .card::after {}
.card::after {
filter: blur(8px); /* gives a softer effect. */
}
@propery rule
We define a CSS variable --angle for controlling the gradient rotation:
@property --angle {
syntax: "<angle>";
initial-value: 0deg;
inherits: true;
}
.card::before, .card::after {
background: conic-gradient(
from var(--angle) at center,
red,
orange,
blue,
purple,
red
);
/* as it were */
}
@keyframes rule
The conic gradient now rotates a full circle every 4 seconds!
Feel free to tweak the speed or colours to your heart desires.
.card::before, .card::after {
/* as it were */
animation: rotate 4s linear infinite;
}
@keyframes rotate {
to {
--angle: 360deg;
}
}
Note
The @property rule is currently best supported in Chromium browsers. If you need broader compatibility, you can animate using other techniques such as transform or animating a mask.
Full Source Code
If you build something cool with this idea, drop a link.
I’d love to check it out!
If you also have any suggestions or recommendations feel free to reach out.
Follow me for more beginner-friendly CSS UI tricks


Top comments (0)