Why bother animating border-image at all?

Most devs treat border-image as that dusty CSS property from 2012 that nobody uses. Big mistake. It gives you image-based (or gradient-based) borders with zero extra DOM nodes and zero pseudo-elements — a huge win when your card component already has a ::before and ::after doing other work.

The catch? Border images don't follow border-radius. If you need a curved animated ring, you're better off with a mask approach. But if you want a sharp, efficient, tileable border animation that runs on a single element, border-image is genuinely hard to beat.

Let's build one from scratch.

The HTML

Nothing fancy here — just a card with some content:

<div class="card">
  <div class="card__content">Bruce Wayne</div>
</div>

The visual (the character image) is set as a background, so let's jump into the CSS.

Developer inspecting CSS border-image animation on a browser devtools panel Dev Environment Setup

Base styles and the border-image setup

We start with the card dimensions and a background image, then layer in the border-image longhands one at a time so you can see exactly which property does what.

.card {
  width: 150px;
  aspect-ratio: 0.69;
  position: relative;
  background: center / 90% no-repeat;
  background-image: url("batman.jpg");

  /* 1. What paints the border: a linear gradient */
  border-image-source: linear-gradient(-45deg, red var(--p, 0%), transparent 0%);

  /* 2. How the gradient is carved into 9 slices */
  border-image-slice: 1;

  /* 3. Physical thickness of the border */
  border-image-width: 5px;

  /* 4. Push the border outward, away from the box */
  border-image-outset: 5px;
}

Key mental model:

  • border-image-slice: 1 means "cut the source image into 1px slices and stretch the middle." For a gradient this produces a smooth fill across the whole border.
  • border-image-width is what actually renders the border. Without it, nothing shows.
  • border-image-outset is your friend when the border clips too close to the content.

Registering a custom property so we can animate it

Here's the gotcha that trips people up: gradients are not animatable by default. You can't transition linear-gradient(red, blue) to linear-gradient(red, blue, green) — the browser has no idea how to interpolate the stop positions.

The fix is @property. Register a custom property with a typed syntax and now the browser knows how to tween it:

@property --p {
  syntax: "<percentage>";
  initial-value: 0%;
  inherits: false;
}

Drop it into the gradient and transition it on hover:

.card {
  border-image-source: linear-gradient(-45deg, red var(--p), transparent 0%);
  transition: --p 0.6s ease-out;
}

.card:hover {
  --p: 100%;
}

The red stop slides from 0% to 100%, giving the illusion that the border is drawing itself. That's the whole trick.

UI designer previewing animated gradient borders on a card component in a code editor Software Concept Art

Leveling up: conic gradients and animated slices

Linear is just the warmup. Swap in a conic-gradient and animate the slice count too, and you get a spinning, tiled border that looks like a loading indicator on steroids.

/* Two more registered custom properties */
@property --n {
  syntax: "<number>";
  initial-value: 1;
  inherits: false;
}

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

.card {
  border-image-source: conic-gradient(from var(--a), red var(--a), transparent 0%);
  border-image-width: 5px;
  border-image-slice: var(--n);
  border-image-repeat: round; /* tile slices without clipping */

  /* Be explicit about what transitions — good for perf */
  transition-property: --n, --a;
  transition-duration: 0.6s;
}

.card:hover {
  --n: 20;      /* deeper slices = visible tiling */
  --a: 360deg;  /* full rotation = border draws itself in */
}

Watch out for these

  • No border-radius support. If your design needs curved corners, this technique is the wrong tool. Use a mask or an SVG stroke instead.
  • Browser support for @property is solid in Chrome/Edge/Safari 16.4+ and Firefox 128+, but always feature-detect with @supports if you're targeting older Safari.
  • border-image-slice animations can be janky on low-end mobile GPUs. Test on a real device, not just DevTools throttling.
  • Don't animate border-image-width — it triggers layout. Stick to paint-only properties.

Front-end dev workstation showing CSS @property and border-image-slice code snippets Algorithm Concept Visual

Where to go next

Once you're comfortable with single gradients, try layering two border-image-source gradients with mask to get multi-color sweeps, or combine this with @scroll-timeline for scroll-driven border animations.

For a deeper look at modern CSS feature techniques like this one, check out our Gemini CLI Plan Mode deep dive — same energy, different tool.

And if you're working with data-heavy UIs where the card content is dynamic, pair this with a solid understanding of Pandas loc vs iloc for DataFrame indexing so your backend stays as clean as your frontend.

Your homework: fork the demo, swap the gradient for a repeating radial-gradient, and see what happens. The results are usually surprising.

Source: css-tricks.com

This content was drafted using AI tools based on reliable sources, and has been reviewed by our editorial team before publication. It is not intended to replace professional advice.