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
-
Link + icon. Link block (
section_link): flex-centered,7remsquare, dark background,border-radius: 100%. Inside, an embed with your SVG (pathfill: currentColor),display: flex. Put the color on the link (not the embed), add afont-colortransition (0.8s expo), and set the hover-state color. -
Fake-border wrapper. Wrap the link in
section_link-wrapper: slightly larger square, flex-centered,border-radius: 100%. Add the attributedata-animate-link-border. -
The CSS. Add an embed on the body with the
@property+ conic-gradient CSS above (set itdisplay: noneand drag it above the section so it loads first). -
Register the class. Add a hidden
divwith theon-hoverclass (ideally in a style guide) so Webflow keeps it and GSAP can toggle it. -
The interaction. Add
data-animate-linkto the link. Create a hover interaction with mouse-enter + mouse-leave; a set action that toggles theon-hoverclass, targetdata-animate-link-borderfiltered 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.