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. Here’s the exact CSS from the cloneable:

<!-- Embed on the body, dragged above the section so it loads first -->
<style>
  @property --fill {
    syntax: '<percentage>';
    inherits: true;
    initial-value: 0%;
  }

  [data-animate-link-border] {
    transition: --fill 0.8s cubic-bezier(.19, 1, .22, 1);
    background: conic-gradient(greenyellow var(--fill), transparent var(--fill));

    &.on-hover {
      --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 CSS above is the exact block from the cloneable — it fills with the greenyellow keyword and an expo ease; swap the color to taste.

Resources

In the knowledge base

Reference pages derived from this lesson — the same material reorganised by concept, so you can look one thing up without rewatching. In English.

  • Target filters — resolving a target relative to the trigger

    An action's target is not one setting but three composed into a sentence — what to target, a filter, and the element the filter is measured against — so "the sidebar that is the previous sibling of the trigger" is Previous sibling of + Trigger element, not a single menu option; this is what lets one interaction serve every card in a CMS collection.

  • Draw a border on hover with a conic gradient

    There is no border — a slightly larger wrapper behind the element leaves a visible ring, filled by a conic gradient whose fill percentage is registered with @property so it can actually transition; GSAP's only job is toggling one class on the hovered instance's wrapper.

  • A style cleanup deletes the classes your interactions toggle

    A class that exists only to be added by a GSAP set action is applied to no element, so Webflow flags it as unused and any style cleanup deletes it — publishing itself does not strip it, which means this breaks work that was already correct, later, when someone tidies the project; keep an element wearing the class so it is genuinely used and never appears in a cleanup list.

  • It works in the Designer but not live — or the reverse

    Custom code, non-standard CSS properties, first-paint flicker, scroll lock and keyboard focus all behave differently in the Designer and in plain preview than on the published site, and the Designer additionally shows you your animations' initial states, so half-hidden content while building is expected rather than broken.

  • Verified identifiers

    Every exact attribute name, class name, variable name, SVG id and selector used across the GSAP-in-Webflow corpus, each traced to the cloneable it was copied from; copy these verbatim and never reconstruct one from memory, because a wrong identifier fails silently.

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.