- Create a gradient border in CSS
- Pseudo element
- Positioning trick
- Masking trick
- Background clip
- Demo
- Border with gradient and radius
- Explanation
- That’s it!
- Border Gradient with Border Radius
- 3 Answers 3
- SVG method
- CSS Mask method
- 2023 — single element, no pseudo elements, no SVG, no masks.
- Linked
- Related
- Hot Network Questions
- Subscribe to RSS
Create a gradient border in CSS
To show gradients for a border with CSS you can use the border-image property. It allows setting gradient values in the same way as the background-image property.
Besides the border-image property, you should specify additional properties to actually show border gradient.
We can combine these properties into a shorthand syntax border-width with border-style into border and border-image-source with border-image-slice into border-image .
.gradient-border border: 5px solid; border-image: linear-gradient(45deg, purple, orange) 1; >
Now you have a nice looking gradient border. And you can use all types of gradients: linear-gradient , radial-gradient and conic-gradient .
However, there’s a drawback to this approach. You cannot use border-radius property, as it is not supported with the border-image property. But there are a few workarounds.
Pseudo element
Positioning trick
For this approach, we need to add a gradient as a background-image for the pseudo-element. Additionally, we need to set its position to absolute and set a negative margin, that will represent the border width. Give it a negative z-index to make it below the main element. And finally, make it inherit border-radius from the main element.
For the initial element, we need to set the required border-radius . Set background color, to match the body background. Optionally we give it a margin to make it within the boundaries of the container because pseudo-element has a negative margin.
.gradient-border-pseudo position: relative; padding: 10px 20px; background: #fff; margin: 5px; border-radius: 5px; > .gradient-border-pseudo::after content: ""; position: absolute; top: 0; right: 0; bottom: 0; left: 0; z-index: -1; margin: -5px; border-radius: inherit; background-image: linear-gradient(45deg, purple, orange); >
Masking trick
For this solution, we’ll also use the pseudo-element, but instead of positioning it with z-index , we will use the mask property to clip the background.
The mask CSS shorthand property hides an element (partially or fully) by masking or clipping the image at specific points.
— MDN
While the mask property may lack full support, you can use this approach for the gradient border.
We’ll set the element’s background as a gradient. And then using mask property we’ll specify two more gradient backgrounds (same color as body ). The first one will mask (cover) the area within the padding boundaries, and the second one will mask (cover) the area all the way up to the border.
Additionally, we need to set the mask-composite property to exclude the top layer from the bottom in order to see the border.
.gradient-border-mask position: relative; padding: 15px 20px; > .gradient-border-mask::before content: ""; position: absolute; top: 0; left: 0; right: 0; bottom: 0; border-radius: 50px; border: 5px solid transparent; background: linear-gradient(45deg,purple,orange) border-box; -webkit-mask: linear-gradient(#fff 0 0) padding-box, linear-gradient(#fff 0 0); -webkit-mask-composite: destination-out; mask-composite: exclude; >
Background clip
To avoid additional styles for pseudo-element you can use the background-image property in combination with background-clip property.
The background-clip CSS property sets whether an element’s background extends underneath its border box, padding box, or content box.
— MDN
Essentially we’re going to clip the background in the similar way we did with the mask property.
First, we’ll need to pass two gradients values for the background-image . One will represent the background of the element with the according color, and the second one will represent the border with gradient.
For each of the gradients, we’ll specify the background-clip property.
For the first one, the value will be padding-box , so the background will extend up until the border.
For the second one, the value will be border-box , which means that the background will extend to the outside edge of the border.
Finally we need to specify a transparent border color and border-radius , and it’s done.
.gradient-border-bg background: linear-gradient(#fff, #fff) padding-box, linear-gradient(45deg, slateblue, coral) border-box; border: 5px solid transparent; border-radius: 50px; >
💡 NOTE: To control the inner border-radius while maintaining the gradient you should use a slightly different approach. Check out my article on inner border-radius.
Demo
Complete examples with code available on CodePen:
See the Pen Untitled by Tippingpoint Dev (@tippingpointdev) on CodePen.
Border with gradient and radius
Unfortunately, border-radius isn’t supported with border-image and it’s painful to find tricks to obtain rounded borders having a gradient. Here is a trick that will produce such a result. No complex code, No SVG, or multiple elements are required! only two lines of CSS code using the mask property.
.box border-radius: 50px; /*1*/ border: 10px solid transparent; /*2*/ background: linear-gradient(45deg,red,blue) border-box; /*3*/ -webkit-mask: /*4*/ linear-gradient(#fff 0 0) padding-box, linear-gradient(#fff 0 0); -webkit-mask-composite: xor; /*5'*/ mask-composite: exclude; /*5*/ >
Explanation
(1)(2): Those lines are trivial.
(3): We apply a gradient as background and we make its origin the border box (by default it’s the padding box).
(4): Using the mask property, we apply two opaque layers. The bottom one will cover the whole element and the top one will cover only the padding box (so it will not cover the border area)
(5): We exclude the top layer from the bottom one so that only the border area will be shown!
(5′): Some browsers still don’t support mask-composite so we use the prefixed version.
That’s it!
Now you can adjust the border, gradient, and radius as you want. The only drawback is that this will mask the content so we can move the code to a pseudo-element instead
.box position: relative; > .box::before content: ""; position: absolute; inset: 0; border-radius: 50px; padding: 10px; background:linear-gradient(45deg,red,blue); -webkit-mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0); -webkit-mask-composite: xor; mask-composite: exclude; >
I replaced the border with padding to make the code shorter but the logic remains the same: we exclude the content area from the padding area so only padding will remain visible
Border Gradient with Border Radius
Adding border-radius: 5px doesn’t seem to do anything. I figured it’s because I’m using a border gradient. is there a way for me to achieve the desired 5px border radius at all?
3 Answers 3
2021: I recommend using the CSS mask method since the support is pretty good now
You cannot use border-radius with gradient. Here is another idea where you can rely on multiple background and adjust the background-clip :
Some text here Some long long long text here Some long long
long text here
SVG method
If you want transparency, you can consider SVG like below:
That you can apply as background:
.white-grad < background:url('data:image/svg+xml;utf8,'); color: #313149; padding:25px; border-radius:15px; display:inline-block; margin: 75px 0; > body
Some text here text very loooooooooooong here
And the same way as mask where you can get the gradient outside of the SVG:
.white-grad < color: #313149; padding: 25px; border-radius: 15px; display: inline-block; margin: 75px 0; background-size: 0 0; position: relative; z-index: 0; >.white-grad::before < content: ""; position: absolute; z-index: -1; top: 0; left: 0; right: 0; bottom: 0; background-image: inherit; background-size: auto; --mask: url('data:image/svg+xml;utf8,'); -webkit-mask: var(--mask); mask: var(--mask); > body
Some text here text very loooooooooooong here text very
loooooooooooong here
You can also use it as common element and consider position:absolute to place it around the text:
.white-grad < color: #313149; padding: 25px; border-radius: 15px; display: inline-block; margin: 75px 0; position:relative; z-index:0; >.white-grad > svg < position:absolute; top:0; left:0; height:100%; width:100%; z-index:-1; >body < background: yellow; >.hide
Some text here text very loooooooooooong here
CSS Mask method
Here is a different idea with CSS using mask where you will have transparency and it will also be responsive:
.white-grad < color: #313149; padding: 10px; display: inline-block; margin: 75px 0; position: relative; z-index: 0; >.white-grad:before
Some text here Some long long long text here Some long long
long text here
With CSS variables, we can make it easy to adjust:
.white-grad < --b:5px; /* border width*/ --r:15px; /* the radius */ color: #313149; padding: calc(var(--b) + 5px); display: inline-block; margin: 75px 0; position:relative; z-index:0; >.white-grad:before < content: ""; position: absolute; z-index: -1; inset: 0; padding: var(--b); border-radius: var(--r); background: var(--c,linear-gradient(to right, #9c20aa, #fb3570)); -webkit-mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0); mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0); -webkit-mask-composite: xor; mask-composite: exclude; >body
Some text here Some long long long text here Some long long
long text here Some long long
long text here
more and more more and more
The above examples cover also the circle shape:
.white-grad < --b:5px; /* border width*/ color: #313149; display: inline-block; margin: 10px; width: 150px; aspect-ratio: 1; position: relative; z-index: 0; >.white-grad:before < content:""; position:absolute; z-index:-1; inset: 0; background: var(--c,linear-gradient(to right, #9c20aa, #fb3570)); padding: var(--b); border-radius: 50%; -webkit-mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0); mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0); -webkit-mask-composite: xor; mask-composite: exclude; >body
Related question in case you want to apply an animation to the border: Button with transparent background and rotating gradient border
Also different radius shapes:
.white-grad < --b:5px; /* border width*/ color: #313149; display: inline-block; margin: 10px; width: 150px; aspect-ratio: 1; position: relative; z-index: 0; >.white-grad:before < content: ""; position: absolute; z-index: -1; inset: 0; background: var(--c,linear-gradient(to right, #9c20aa, #fb3570)); padding: var(--b); border-radius: var(--r,50%); -webkit-mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0); mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0); -webkit-mask-composite: xor; mask-composite: exclude; >body
and different border thickness:
.white-grad < --b:5px; /* border width*/ color: #313149; display: inline-block; margin: 10px; width: 150px; aspect-ratio: 1; position: relative; z-index: 0; >.white-grad:before < content: ""; position: absolute; z-index: -1; inset: 0; background: var(--c,linear-gradient(#9c20aa, #fb3570)); padding: var(--b); border-radius:var(--r,50%); -webkit-mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0); mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0); -webkit-mask-composite: xor; mask-composite: exclude; >body
I love you. @NoéVIRICEL if you change the #ccc value in the first linear-gradient to transparent, that should work
@mikespitz_8 the first one won’t work with transparency, you need to consider the other solutions for transparency (the SVG or the mask)
This is really cool, but it seems that if the box background and page background are different colors, the page background square corner will stick out from behind the border.
What are the —b , —r , and —c attributes are called? They look like a shorthand but I can’t find reference to it anywhere. Thank you for this wonderful answer.
2023 — single element, no pseudo elements, no SVG, no masks.
I can’t take credit for this, I saw this on a website (I forgot the site and can’t find it again).
- It’s just a normal button with rounded edges and a gradient background
- It uses a box-shadow that is inset to fill the inside with white
- It has a 2px border which is actually transparent, so the very edge of the button shows through
and «No transparency» as well. My top answer is already giving a less hacky method with no transparency
@TemaniAfif if you want some actual feedback on your answer, which will have made my own answer redundant so I can delete it. 1. put the best CSS Mask method first. 2. don’t use ‘white-grad’ (which is presumably white-gradient) where no white gradient exists. If you do that, I’ll delete my own answer.
You need to wrap the button in a div and set the border-radius on that parent div. In order to work, you will have to set overflow:hidden to that parent div as well. Like so:
Highly active question. Earn 10 reputation (not counting the association bonus) in order to answer this question. The reputation requirement helps protect this question from spam and non-answer activity.
Linked
Related
Hot Network Questions
Subscribe to RSS
To subscribe to this RSS feed, copy and paste this URL into your RSS reader.
Site design / logo © 2023 Stack Exchange Inc; user contributions licensed under CC BY-SA . rev 2023.7.20.43540
By clicking “Accept all cookies”, you agree Stack Exchange can store cookies on your device and disclose information in accordance with our Cookie Policy.