Growing Border Hover Animation in Webflow (CSS + GSAP)

Intermediate 16:32 webflowgsapcsshoverconic-gradient

Build a growing circular border on hover in Webflow with a conic-gradient and an animatable @property; GSAP just toggles a class while CSS does the animation.

Key takeaways

  • GSAP doesn't animate the border here — it just toggles a class, and CSS does the whole animation. Cleaner and lighter than driving it from JavaScript.
  • The "border" is fake: a slightly larger wrapper whose conic-gradient background peeks around the inner circle, so growing the gradient looks like a border drawing itself on.
  • Plain CSS variables don't animate, but a registered @property (syntax percentage, initial 0%) does — that's what lets the conic-gradient fill transition smoothly.
  • Set the SVG fill to currentColor and put the color on the parent link (not the icon) so a single font-color transition recolors the icon on hover.
  • Attribute targeting plus a "direct parent of trigger" filter means one hover interaction animates only the hovered link's border — and the whole setup is instantly reusable.

Video chapters

  1. 00:00 Intro
  2. 01:00 Setting up the structure
  3. 03:54 Creating the icon color hover effect
  4. 05:39 HTML setup for the growing border animation
  5. 07:18 CSS setup for the growing border animation
  6. 11:31 GSAP setup for the growing border animation
  7. 15:26 Outro

This is one of those hover effects that looks fancy but runs on almost no code: a smooth circular border that grows around a social link, in sync with the icon shifting color. The twist is that GSAP never animates the border at all — it just flips a class on and off, and CSS handles the entire animation behind the scenes.

It’s a great little showcase of two underused CSS features — conic gradients and the @property rule — plus the recurring theme of this course: reach for GSAP only where you actually need it.

How it works

The icon color is pure CSS. The link is a circle (display: flex, centered, border-radius: 100%, dark background) with an SVG icon whose path uses fill: currentColor. The catch: set the color on the icon’s own embed and it overrides the inherited value, so a hover on the parent won’t reach it. Put the color on the parent link instead, add a font-color transition, and set the hover-state color — now the icon inherits and animates gray → green on hover, no JavaScript.

The border is an illusion. There’s no border property anywhere. Wrap the link in a slightly larger circle (section_link-wrapper, border-radius: 100%); the inner link covers most of it, leaving only a thin ring visible. Give that ring a conic-gradient background (conic because color spreads radially around a circle), and animate how far the gradient fills — from nothing to all the way around — and it reads as a border drawing itself on.

@property makes the gradient animatable. You can’t smoothly transition an ordinary CSS variable — browsers treat it as text. So register the fill amount with the @property rule (syntax: '<percentage>', inherits: true, initial-value: 0%), which tells the browser it’s a real, typed value. Put a transition on that property (0.8s, expo) and a rule that sets it to 100% when an on-hover class is present. Roughly:

<!-- Embed on the body, loaded before the section -->
<style>
  @property --double-fill {
    syntax: '<percentage>';
    inherits: true;
    initial-value: 0%;
  }
  [data-animate-link-border] {
    transition: --double-fill 0.8s cubic-bezier(0.16, 1, 0.3, 1);
    background: conic-gradient(var(--green-yellow) var(--double-fill), transparent 0);
  }
  [data-animate-link-border].on-hover {
    --double-fill: 100%;
  }
</style>

GSAP’s only job is the class. A hover interaction (mouse-enter + mouse-leave) uses a set action to toggle the on-hover class on the wrapper — targeted by data-animate-link-border with a direct parent of trigger filter so only the hovered link’s wrapper is affected. The CSS transition does the rest: fill to 100% on enter, back to 0% on leave. Because it’s attribute-driven, duplicating the link “just works” — each one animates independently.

How to use it

  1. Link + icon. Link block (section_link): flex-centered, 7rem square, dark background, border-radius: 100%. Inside, an embed with your SVG (path fill: currentColor), display: flex. Put the color on the link (not the embed), add a font-color transition (0.8s expo), and set the hover-state color.

  2. Fake-border wrapper. Wrap the link in section_link-wrapper: slightly larger square, flex-centered, border-radius: 100%. Add the attribute data-animate-link-border.

  3. The CSS. Add an embed on the body with the @property + conic-gradient CSS above (set it display: none and drag it above the section so it loads first).

  4. Register the class. Add a hidden div with the on-hover class (ideally in a style guide) so Webflow keeps it and GSAP can toggle it.

  5. The interaction. Add data-animate-link to the link. Create a hover interaction with mouse-enter + mouse-leave; a set action that toggles the on-hover class, target data-animate-link-border filtered by direct parent of trigger. Enable custom code (or publish) to test — non-standard CSS doesn’t run in plain preview.

The exact CSS (colors, gradient stops) lives in the cloneable — the snippet above is the shape of it; confirm the values against the cloneable.

Resources

Frequently asked questions

How do I animate a border growing around a circular element in Webflow?
Don't animate a border property. Wrap the element in a slightly larger circle whose background is a conic-gradient, and animate how far that gradient fills. As the fill grows from 0% to 100%, the color wraps around the circle and looks like a border drawing itself on.
Why use @property instead of a normal CSS variable for this?
Browsers treat ordinary CSS variables as plain text, so they can't always transition smoothly. Registering the value with @property (syntax: '<percentage>', initial-value: 0%) tells the browser it's a real, typed, animatable value — which is what makes the conic-gradient fill animate.
Should GSAP animate the border directly?
No — and that's the point. GSAP only toggles an on-hover class with a set action; the CSS transition on the registered property does the actual animation. It's lighter and simpler than animating the value from JavaScript, and it keeps the motion in CSS where it belongs.
How do I recolor an SVG icon on hover in Webflow?
Give the SVG path fill: currentColor, then set the color on the parent link rather than on the icon's own embed (a color set directly on the embed overrides the inherited one). Add a font-color transition on the link and set the hover-state color — the icon now animates its color on hover with no JavaScript.

← Back to the course