EmpireUI
Get Pro
← Blog8 min read#gradient border#css#border-image

Gradient Border in CSS: border-image, pseudo-elements and conic-gradient

Three battle-tested CSS techniques for gradient borders — border-image, ::before pseudo-elements, and conic-gradient — with code you can copy today.

colorful gradient stripes on a dark background showing CSS border effects

Why CSS Gradient Borders Are Trickier Than They Look

You'd think border: 2px solid gradient(...) would just work. It doesn't. CSS has never had a first-class gradient border property, which means you're always one layer of abstraction away from the effect you actually want. That gap between intent and implementation is exactly why so many Stack Overflow answers from 2019 are still getting upvotes.

There are three main approaches: border-image with a gradient value, a ::before or ::after pseudo-element acting as a fake border, and the newer conic-gradient trick for animated spinning borders. Each one has real trade-offs around border-radius, background-clip, and browser support — and picking the wrong one will cost you two hours of debugging.

In practice, I reach for the pseudo-element approach about 80% of the time because it's the only one that plays nicely with border-radius. But let's walk through all three so you actually understand what you're choosing between.

The border-image Approach (Fast, But Limited)

border-image has been in browsers since Chrome 15, Firefox 3.5 — it's not new. The syntax looks like this:

.card {
  border: 3px solid transparent;
  border-image: linear-gradient(135deg, #f857a6, #ff5858) 1;
}

The trailing 1 is the border-image-slice value. It tells the browser to use the full gradient as a single slice rather than splitting it into nine sections for a border-image pattern. Dead simple.

Worth noting: border-image completely kills border-radius. The moment you add border-radius: 12px to that card, the gradient border snaps back to sharp corners. That's not a browser bug — it's how the spec works. The gradient is rendered as an image and sliced, and images don't know anything about border-radius. If your design needs rounded corners, stop here and skip to the pseudo-element section.

That said, border-image is genuinely useful for rectangular UI — data tables, code blocks, HUD-style panels in a cyberpunk or tech-heavy design system. No extra DOM nodes, no z-index gymnastics.

The Pseudo-element Approach (Most Flexible)

This is the technique you'll use for cards, modals, and anything with rounded corners. The idea: make the element position: relative, then use ::before as an absolutely-positioned layer behind the element that's slightly larger and has the gradient as its background. The inner element's background clips the visual to create the illusion of a border.

.card {
  position: relative;
  background: #0f0f0f;
  border-radius: 16px;
  padding: 24px;
  z-index: 0;
}

.card::before {
  content: '';
  position: absolute;
  inset: -2px; /* controls border thickness */
  border-radius: 18px; /* parent radius + border thickness */
  background: linear-gradient(135deg, #667eea, #764ba2, #f093fb);
  z-index: -1;
}

The inset: -2px shorthand (equivalent to top: -2px; right: -2px; bottom: -2px; left: -2px) is available since Chrome 87. If you're still targeting older Chromium builds, use the longhand. The key gotcha is border-radius on the pseudo-element: it needs to be the parent's radius plus the border thickness, otherwise you'll see background color bleeding through at the corners.

Honestly, this approach gives you total creative control. Want the gradient to animate? Throw a @keyframes on background-position with a large background-size. Want the border to glow? Combine it with box-shadow on the ::before. You can see how this layering fits into heavier glass effects over at glassmorphism components, where the border highlight is often what sells the depth.

One more thing — if your element already uses ::before or ::after for something else (like a tooltip arrow or decorative icon), you're stuck. You either refactor or wrap the element in another div. That's the one real downside.

conic-gradient for Spinning Border Animations

The spinning gradient border became a viral UI pattern around 2023, and it's still everywhere. The effect looks like a glowing cone rotating around your card's perimeter. Here's the approach that actually works without JavaScript:

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

@keyframes rotate-border {
  to { --angle: 360deg; }
}

.spinning-card {
  position: relative;
  background: #111;
  border-radius: 12px;
  padding: 32px;
}

.spinning-card::before {
  content: '';
  position: absolute;
  inset: -2px;
  border-radius: 14px;
  background: conic-gradient(
    from var(--angle),
    transparent 70%,
    #00d4ff,
    #7b2ff7,
    transparent
  );
  animation: rotate-border 3s linear infinite;
  z-index: -1;
}

That @property declaration is doing the heavy lifting. Without it, CSS can't interpolate --angle because it doesn't know the variable's type — the animation just jumps between keyframes instead of rotating smoothly. @property landed in Chrome 85 and Firefox 128, so browser support is solid in 2026 as long as you're not targeting legacy enterprise environments.

Quick aside: the conic-gradient portion that's transparent 70% controls how much of the cone is visible. 70% transparent means only 30% of the rotation arc shows the actual gradient colors. Tweak that number and you control whether you get a thin glowing arc or a nearly full ring.

For a darker, more high-contrast version of this, try combining it with the aurora color palette from aurora backgrounds. The blue-purple-teal range reads beautifully as a spinning border on dark cards and doesn't require any extra libraries.

background-clip: text — Gradient Borders on Text (Bonus Trick)

While we're here, gradient borders on text headings are a related pattern worth knowing. It's not border-image — it's background-clip: text combined with a transparent text color:

.gradient-heading {
  background: linear-gradient(90deg, #f857a6 0%, #ff5858 50%, #ffba08 100%);
  -webkit-background-clip: text;
  -webkit-text-fill-color: transparent;
  background-clip: text;
  color: transparent;
}

Strictly speaking this isn't a border effect, but it comes up in the same design context — cards with gradient titles sitting next to gradient-bordered containers. The two patterns pair naturally. You can also use our gradient generator to build the linear-gradient value visually and copy it straight into your CSS.

Putting It All Together: When to Use Which

Let's be direct about the decision tree. Does your element need border-radius? Skip border-image, use pseudo-elements. Do you need the border to animate with a spinning or sweeping effect? Use conic-gradient with @property. Is your element a simple rectangle and you just need a quick gradient stroke? border-image is two lines and done.

There's also a fourth approach worth knowing: outline with a gradient doesn't exist (outline doesn't support gradient values), but box-shadow layering can fake multi-stop colored glows around an element that reads as a border. It's blurry by definition, so it's more of a glow than a border, but in contexts like neumorphism design it works perfectly because the soft shadow is already the point.

For production components, I'd default to the pseudo-element approach every time. It's the most maintainable, it handles border-radius, and it gives you a surface to attach animations later without rewriting the core styles. The border-image trick is great for quick prototyping or design-system tokens where you know the shapes are always rectangular.

Look, no single technique wins in all scenarios — and that's fine. CSS gradient borders are an area where knowing all three approaches actually matters rather than just picking one and committing. If you want to see these patterns applied at component-library scale, browse components to see how Empire UI handles border accents across different visual styles.

FAQ

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

It's specced behavior, not a bug. border-image renders a sliced image that gets drawn over the border box — it doesn't respect the shape defined by border-radius. Use the pseudo-element technique if you need rounded corners.

Can I animate a gradient border without @property?

Sort of. You can animate background-position on a large background-size gradient, which gives a sliding color shift. For true rotation you need @property to interpolate custom angle variables — without it CSS won't tween the angle.

Does border-image affect layout or just visuals?

Just visuals. The border still occupies the same space in the box model — border-image only changes how that border space is painted, not its thickness or its effect on layout.

Is there a performance difference between these approaches?

The conic-gradient animation is the heaviest because it triggers repaints on each frame. Use will-change: transform on the pseudo-element to promote it to its own compositor layer and keep frame rates smooth on mid-range hardware.

Free components in 40 styles
React & Tailwind, copy-paste ready.
Browse →

Read next

Animated Gradient Border in CSS: Spinning Rainbow Border on Any ElementGradient Card Design in React: Mesh, Conic and Radial ApproachesTailwind Gradient Text: bg-clip-text in Under 2 MinutesCSS border-radius Patterns: From Rounded to Blob Shapes