Adding a Gooey Menu Hover Effect with GSAP
Leroy · 1 Jun 2026 · 2 min read
The Idea
I wanted the navigation menu on this blog to feel alive. When you hover over a link, a blob stretches and slides to it with a liquid-like motion. Like honey or warm gum. Not just a color change or underline, but something tactile and playful.
The Technique
The effect combines two things.
- GSAP (GreenSock Animation Platform) handles the smooth tweening of the blob's position and width with
power2.outeasing for that deceleration feel. - An SVG gooey filter (
feGaussianBlur+feColorMatrix) creates the liquid stretch effect where the blob appears to ooze between links.
How It Works
When you hover over a nav link, a small JavaScript function measures the link's position and size using getBoundingClientRect(), then tells GSAP to animate the blob to those coordinates:
function moveBlob(target) {
var rect = target.getBoundingClientRect();
var navRect = nav.getBoundingClientRect();
gsap.to(blob, {
left: rect.left - navRect.left - 8,
width: rect.width + 16,
opacity: 1,
duration: 0.4,
ease: 'power2.out'
});
}
The SVG filter is the key. It lives as an inline SVG in the page body:
<svg style="position:absolute;width:0;height:0;" aria-hidden="true">
<defs>
<filter id="goo">
<feGaussianBlur in="SourceGraphic" stdDeviation="10" result="blur" />
<feColorMatrix in="blur" mode="matrix"
values="1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 18 -7" result="goo" />
<feBlend in="SourceGraphic" in2="goo" />
</filter>
</defs>
</svg>
feGaussianBlur softens the edges of the blob. feColorMatrix sharpens them back with a threshold. That creates the gooey merging effect where the blob appears to flow.
Why GSAP from CDN?
This project has no JavaScript bundler. It is a Go server that serves static files. Adding webpack or esbuild just for one animation felt like overkill. GSAP's CDN is fast, version-pinned, and about 30KB gzipped. No build step.
Accessibility
prefers-reduced-motion: the animation disables itself if the user has this preference set.- Keyboard navigation: the blob follows tab focus, not just mouse hover.
- Touch devices: the animation is disabled on touch screens to avoid flickering before page navigation.
- Screen readers: the blob element has
aria-hidden="true"and the SVG filter is visually hidden.
Dark Mode Compatibility
The blob uses the theme's --accent CSS variable at 30% opacity via color-mix(). It adapts to both light and dark themes without extra code.
The Result
Hover over the navigation links at the top of this page. The blob slides with a satisfying deceleration, stretching between links that are close together. A small touch that makes the site feel more polished.