CSS and web

CSS gradient border: four ways to draw one

border-color does not take a gradient, so every gradient outline is a workaround. Here are the four that matter, what each can and cannot do, and which to reach for.

GradientlyVerified Gradiently account··5 min read
Cover: Inner Reel · GR·WQK6·T2

The short version

  • CSS cannot put a gradient in border-color, so a CSS gradient border is always drawn with another technique.
  • border-image with a gradient is the shortest method, but it ignores border-radius, so it only suits square corners.
  • Two background layers, one clipped to the padding box and one to the border box, give a rounded gradient border as long as the inside is a solid colour.
  • The mask technique cuts the middle out of a gradient layer, which gives a rounded gradient border with a transparent inside.
  • A rotating conic gradient, driven by a custom property registered with @property, is the usual way to animate a gradient border.
On this page

A CSS gradient border is an outline whose colour blends along its length. The catch is that border-color only takes colours, not images, so there is no single property for it. Instead you draw the gradient somewhere else and show only a thin band of it. There are four reliable ways to do that, and the right one depends on two questions: does the element have rounded corners, and does its inside need to be transparent?

MethodRounded cornersTransparent insideBest for
border-imageNoYesSquare cards, dividers, tables
Two backgroundsYesNo, needs a solid fillMost cards and buttons
Mask on a pseudo-elementYesYesCards over images or gradients
Pseudo-element behindYesNoGlows and animated rings
Choose by the two questions: corners and inside.
Gradients that read well as thin outlines. High saturation matters more on a 2px line than on a whole background.

Method 1: border-image

border-image accepts any image, including a gradient. Set a border width and style, then the gradient, then a slice of 1, which tells the browser to use the whole image as the edge. It is two lines, works everywhere, and keeps the inside of the element untouched.

css
.panel {
  border: 3px solid;
  border-image: linear-gradient(135deg, #7c3aed, #22d3ee) 1;
}
The shortest gradient border. The 1 is the slice value; without it the border draws only in the corners.

Method 2: two backgrounds with background-clip

Give the element a transparent border, then stack two backgrounds. The top layer is the inner fill, clipped to the padding-box, so it stops at the inside edge of the border. The bottom layer is the gradient, clipped to the border-box, so it extends under the border. Where the fill stops, the gradient shows, and it follows border-radius perfectly.

css
.card {
  border: 2px solid transparent;
  border-radius: 16px;
  background:
    linear-gradient(#0f172a, #0f172a) padding-box,
    linear-gradient(135deg, #7c3aed, #22d3ee) border-box;
}
The fill is written as a one-colour gradient because only images can be layered like this.

This is the method to reach for by default. Its one limit is that the inside must be opaque, since a transparent fill would reveal the gradient across the whole card. For cards sitting on a flat page colour, that is no limit at all: use the page colour as the fill.

Method 3: the mask technique for transparent insides

When the card sits over a photo or another gradient, you need the middle to be see-through. Put the gradient on a pseudo-element that covers the card, give it padding equal to the border width, then mask it with two layers: one covering only the content box and one covering everything. Excluding one from the other leaves just the padding ring visible.

css
.glass-card {
  position: relative;
  border-radius: 16px;
}

.glass-card::before {
  content: "";
  position: absolute;
  inset: 0;
  padding: 2px; /* border width */
  border-radius: inherit;
  background: linear-gradient(135deg, #7c3aed, #22d3ee);
  -webkit-mask:
    linear-gradient(#000 0 0) content-box,
    linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
  mask:
    linear-gradient(#000 0 0) content-box exclude,
    linear-gradient(#000 0 0);
  pointer-events: none;
}
A gradient ring with a transparent centre. The prefixed pair covers older WebKit; the standard mask line covers everything current.

pointer-events: none stops the pseudo-element swallowing clicks meant for the card's content. The MDN mask-composite reference explains the compositing keywords. This is the method behind most glassmorphism cards with glowing edges.

Method 4: a pseudo-element behind, for glows and animation

Place a gradient pseudo-element slightly larger than the card, behind its content, and cover the middle with a second pseudo-element holding the card's solid fill. The visible edge is the gradient. Because the gradient lives on its own layer, you can blur a copy of it for a glow, or rotate it.

css
@property --angle {
  syntax: "<angle>";
  inherits: false;
  initial-value: 0deg;
}

.ring {
  position: relative;
  isolation: isolate;
  border-radius: 16px;
}

.ring::before {
  content: "";
  position: absolute;
  inset: -2px;
  z-index: -1;
  border-radius: 18px;
  background: conic-gradient(from var(--angle), #7c3aed, #22d3ee, #f472b6, #7c3aed);
  animation: spin 6s linear infinite;
}

/* the card's fill, painted over the middle of the ring */
.ring::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  border-radius: inherit;
  background: #0f172a;
}

@keyframes spin {
  to { --angle: 360deg; }
}

@media (prefers-reduced-motion: reduce) {
  .ring::before { animation: none; }
}
An animated gradient border. The registered --angle lets the browser interpolate the conic start angle smoothly, and ::after paints the fill over the middle.
The rotating ring's gradientconic-gradient(from 0deg, #7c3aed, #22d3ee, #f472b6, #7c3aed)
Repeating the first colour at the end hides the seam as it turns. CSS conic gradients covers the function in depth.

The outer radius should equal the inner radius plus the border width, which is why the pseudo-element uses 18px around a 16px card. For more ways to put motion into gradients, see CSS animated gradients.

Design tips for gradient borders

Avoid

  • Gradient borders on every card in a grid
  • Low-saturation gradients on a 1px line, which read as grey
  • A gradient border and a gradient fill on the same element
  • Fast spinning rings on content people need to read

Do

  • Reserve the gradient edge for one highlighted item, such as a featured plan
  • Use 2px or more and saturated stops
  • A calm fill with a vivid edge, or the reverse
  • Slow rotation, paused for reduced motion

Gradient borders work best as emphasis. The same logic applies to buttons, covered in gradient buttons in CSS.

Questions people ask

How do I make a gradient border in CSS?

The quickest way is border: 3px solid; border-image: linear-gradient(135deg, #7c3aed, #22d3ee) 1;. For rounded corners, use two backgrounds clipped to padding-box and border-box.

Why doesn't border-radius work with border-image?

By specification, a border drawn with border-image is not rounded by border-radius. Use the background-clip or mask method for rounded gradient borders.

How do I make a gradient border with a transparent background?

Use the mask technique: a pseudo-element with the gradient, padding equal to the border width, and a mask that excludes its content box.

How do I animate a gradient border?

Register an angle with @property, use it as the from angle of a conic gradient on a pseudo-element, and animate that property from 0deg to 360deg.

Which gradient border method should I use?

Use two backgrounds for most rounded cards and buttons, border-image for square edges, and the mask technique only when the inside must stay transparent.

Share this guide

Written by GradientlyVerified Gradiently account

The team behind Gradiently, a design tool built around Marks: living gradients that make everything you design look like yours.

See our profile