How to create a gradient border with rounded corners using CSS
March 23, 2024
I recently needed to create a shiny gradient border for a box that had rounded corners and while there are a few different approaches, I couldn’t find anything documenting using an inset box-shadow
to achieve the effect, so that’s what this short post is about.
If you don’t need rounded corners using border-radius
then the border-image property is probably the easiest approach.
This is what the end result will look like:
If you don’t care about the specifics, here’s a Codepen
This approach works by setting the background of the box to a gradient and then applying an inset box shadow, starting at the top of the box and stretching to the bottom of the box, that is the same colour as the background of the page, that shadow then fills the box all the way to the edges leaving only the border showing the gradient, instead of the entire background.
First you’ll need an outer wrapper and an inner wrapper.
<div class="outer">
<div class="inner">
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
consequat.
</div>
</div>
Then, define your border width and border radius (I’m using css variables to make it easier to read, but feel free to just put the numbers inline)
.outer {
--outer-border-radius: 8px;
--border-width: 2px;
}
.inner {
padding: 16px;
}
Work out the border-radius
for the inner wrapper. (Approach taken from this article on how to create perfect nested border radius)
.outer {
--outer-border-radius: 8px;
--border-width: 2px;
--inner-border-radius: calc(
var(--outer-border-radius) - var(--border-width)
);
}
.inner {
padding: 16px;
}
Set your gradient and apply the border
and border-radius
. Note we use a transparent border here, so that the gradient “background” can eventually show through.
.outer {
--outer-border-radius: 8px;
--border-width: 2px;
--inner-border-radius: calc(
var(--outer-border-radius) - var(--border-width)
);
background-image: linear-gradient(
192deg,
#ff4757 5.4%,
#3742fa 33.68%,
#2ed573 67.8%,
#1e90ff 95.59%
);
border: var(--border-width) solid transparent;
border-radius: var(--outer-border-radius);
}
.inner {
padding: 16px;
border-radius: var(--inner-border-radius);
}
This should result in something like the following:
Now essentially all we need to do is hide everything except the border. The key to this approach is to apply a box-shadow
inside of the box that then fills the entire box leaving only the border showing the gradient.
For this you’ll need a inset
shadow with an xOffset
of 0
and a yOffset
of 100vh
. This is essentially a shadow starting at the top of the box and stretching all the way to the bottom (technically further than the bottom as we’re using vh
units). Try changing it to something like 50px
to see how the effect works.
We also include the background-clip
and background-origin
properties so that the shadow doesn’t escape our box.
.outer {
--outer-border-radius: 8px;
--border-width: 2px;
--inner-border-radius: calc(
var(--outer-border-radius) - var(--border-width)
);
background-image: linear-gradient(
192deg,
#ff4757 5.4%,
#3742fa 33.68%,
#2ed573 67.8%,
#1e90ff 95.59%
);
border: var(--border-width) solid transparent;
border-radius: var(--outer-border-radius);
box-shadow: white 0 100vh inset;
background-clip: border-box;
background-origin: border-box;
}
.inner {
padding: 16px;
border-radius: var(--inner-border-radius);
}
and that’s it 🎉