Guides · · Maxwell Prehoda
12 Navbar Hover Effects From Real Sites and CSS Classics, With Live Demos
The best navbar hover effects do one job: they show which item you are about to pick, and they get out of the way. In practice that means one of four patterns: an underline that draws in, an indicator that slides between items, a dropdown that morphs to fit its content, or a playful effect for sites where personality matters more than speed. Below are 12 examples of those patterns from CSS-Tricks, Codrops, Stripe, Radix and others, plus three of our own pure-CSS versions you can play with right on the page.
Each entry says what it is best for, what it runs on and what will bite you. We opened every source linked here, and where a live demo sits under a third-party entry, it is our pure-CSS take on the pattern, not that author's code.
1. Hover.css underline and overline transitions by Ian Lunn: Best for a classic underline on a marketing site top nav
Platform: CSS, Sass or LESS; MIT for personal use, paid commercial license
Hover.css is one of the oldest and best-known hover libraries on the web. Its Border Transitions group holds the effects most navbars need: Underline From Left, Underline From Center, Underline From Right, Underline Reveal, and the matching Overline variants.
What makes the pattern work is restraint. A 2px line that grows from the centre tells the user exactly where the pointer is without moving any text, so the menu never feels jumpy.
Our Underline from Center Link below is a pure-CSS version of the same idea: a pseudo-element scaled on X, which is cheaper than animating width.
Watch out for: Commercial projects need a paid Hover.css license (the free MIT terms exclude selling the application). Also add a :focus-visible rule that shows the same line, because hover-only underlines leave keyboard users guessing.
5. Vercel-style hover highlight with Motion layoutId: Best for React and Next.js apps with a tabbed top nav
Platform: React + Motion (formerly Framer Motion) + Tailwind
Vercel's dashboard popularised a background pill that follows the pointer across tabs. Ashirvad Bhushan's tutorial rebuilds it in Next.js: a motion.div with a shared layoutId renders only behind the hovered link, and Motion animates it from one link to the next with a spring. As he puts it, each link's background "would follow the cursor on hover over the navbar."
Shared layout animation suits tabs of changing width, because Motion measures the real boxes for you.
If you would rather not ship a JavaScript animation library for this, our Sliding Pill nav below is a pure-CSS version for fixed menus: :has() moves one pill to the hovered item and back to the current page.
Watch out for: The tutorial tracks onMouseOver and onMouseLeave only, so keyboard users get no highlight until you add onFocus and onBlur. Keep the spring bounce low; a wobbling pill on every hover gets tiring fast.
6. Anchor positioning tab underline (Chrome for Developers): Best for zero-JavaScript indicators on modern browsers
Platform: Pure CSS, anchor positioning (Baseline 2026)
CSS anchor positioning lets one element position itself against another, which is exactly what a sliding indicator needs. Chrome's guide gives the active list item anchor-name: --active, then tethers a ::before on the list to it with position-anchor and anchor() insets. A transition on inset makes the line slide when the active item changes.
Temani Afif took the idea further on CSS Tip with two menu hover experiments, one sliding and one jumping, where the anchor follows the hovered item. Per MDN's compatibility data, anchor-name ships in Chrome and Edge 125, Firefox 147 and Safari 26, and MDN lists anchor positioning as Baseline newly available since January 2026.
Watch out for: Do not use position-area for the indicator: the guide notes it cannot be transitioned. Wrap the transition in a prefers-reduced-motion: no-preference query, pair the line with aria-current, and keep a static border fallback behind @supports for older browsers.
7. Stripe's morphing dropdown, rebuilt by Lokesh Dhakar and CodyHouse: Best for SaaS mega menus with panels of different sizes
Platform: CSS transforms + a little JavaScript
Stripe's main navigation is the reference everyone copies: instead of swapping separate dropdowns, one white panel morphs from the size of one menu to the next. Lokesh Dhakar's tutorial explains how: the background box moves with translateX and resizes with scaleX and scaleY, the content lives in a separate sibling so it never stretches, the sections cross-fade on opacity, and the popover swings open from rotateX(-15deg). His timings are 0.4s for the morph and 0.3s for the swing.
The reason it uses transforms is performance. Animating width, height or left makes the browser recalculate layout every frame; his DevTools audit of the transform version found "Zero work on the main thread." CodyHouse's version does the same with a 1px background layer scaled to each panel's pixel size.
Watch out for: Scaling a box also scales its border-radius and shadow, which is why these builds keep the panel's corners and arrow on separate layers. Both write-ups describe Stripe's navigation at the time they were written; the live stripe.com nav may have changed since.
11. Creative Link Effects on Codrops: Best for editorial and agency sites that want character
Platform: HTML + CSS demos, free on Codrops
Manoela Ilic's 2013 collection is a set of experimental link effects built mostly with transitions on ::before and ::after. It is the ancestor of a whole genre of nav hovers where two pseudo-elements do all the work and a plain text menu suddenly feels designed.
Use it for inspiration on a small nav of four or five words, where each hover can afford to be a little theatrical. Our Slide Up Text Link below is a pure-CSS take on the same pseudo-element approach: the label rolls up while a copy from a data attribute rolls in.
Watch out for: Rolling and flipping text is harder to read mid-hover, so keep these for short, familiar labels. Test any effect that duplicates text with a screen reader, and keep the copy in CSS content or aria-hidden markup so it is not announced twice.
How to choose a navbar hover effect
Three questions settle it faster than scrolling through another hundred pens.
Match it to the nav
A short text nav of four or five links suits an underline (Hover.css, our Directional Underline) or a sliding indicator (Magic Line, the Vercel-style pill). A nav with dropdowns of different sizes wants a morph (Stripe's) and real keyboard handling (Radix). Playful effects like the gooey menu or strikethrough belong on portfolios, not on a checkout header.
Match it to the stack
On a static site or a CMS theme, stay in CSS: :has() works in every current major browser, and anchor positioning is now Baseline, with a static fallback for older versions. In a React app that already ships Motion, layoutId is the least code for an indicator. If your mobile nav collapses into a hamburger, the hover effect only exists on desktop, so spend the motion budget on the hamburger menu animation as well.
Match it to the moment
Navs get hovered constantly, so keep transitions between about 150 and 300 milliseconds and use ease-out or a gentle spring. Every effect needs a matching :focus-visible state, and the current page should keep its indicator when nothing is hovered. Turn on reduced motion in your OS and check the nav still shows which item is active without the movement. Our post on CSS animations for microinteractions covers the timing side in more depth.
Ship a better nav hover today
Pick the pattern, not the prettiest pen. For a row of text links, copy an underline or indicator demo above and add a current-page marker and a focus state. If it has dropdowns, start from Radix or the Stripe tutorial and keep the motion to a single morph.
If none of these fit your brand, describe your nav to the creator: it asks a few quick questions while it works and returns production-ready CSS you can refine in chat.
Make a navbar hover effect for a five-link top nav on a dark SaaS header. A pill highlight slides to the hovered link in 220ms with a soft spring and returns to the current page (aria-current) when the pointer leaves. The same highlight appears on :focus-visible for keyboard users. Pure CSS with :has(), no JavaScript, colour and size as custom properties. Under prefers-reduced-motion, the pill jumps without sliding.
Common questions
How do I add a hover effect to a navbar in CSS?
Give each link position: relative and add a ::after pseudo-element for the line or background. Set it to transform: scaleX(0) at rest and scaleX(1) on :hover and :focus-visible, with a transition on transform of about 250ms. Scaling a pseudo-element is smoother than animating width, and it does not shift the text.
How do I make a sliding underline that moves between nav links?
There are three routes. Pure CSS with :has() and a custom property works for menus with equal-width items, like our Sliding Pill. CSS anchor positioning tethers one indicator to whichever item is hovered or active, now Baseline across major browsers. In React, Motion's layoutId moves one element between items and handles any widths.
Do navbar hover effects work on mobile?
Not really. Touch screens have no hover, and most mobile navs collapse into a menu button anyway. Make sure the current page is marked without hover, use @media (hover: hover) to scope hover-only flourishes to devices that support them, and put the mobile motion into the menu toggle instead.
Are navbar hover animations bad for accessibility?
They are fine if three things hold: the same state shows on keyboard focus, the current page is marked with aria-current rather than colour alone, and a prefers-reduced-motion rule removes the movement. Avoid effects that blur or move the other links so much that their labels become hard to read.
How long should a nav hover transition be?
Short: 150 to 300 milliseconds with an ease-out curve feels responsive for links people pass over all the time. Longer, bouncier transitions make a product header feel slow.
Sources
- Hover.css by Ian Lunn
- CSS-Tricks: jQuery MagicLine Navigation (Chris Coyier)
- Lokesh Dhakar: Stripe.com's main navigation
- CodyHouse: Stripe.com navigation
- Radix Primitives: Navigation Menu
- Chrome for Developers: Anchor positioning tab underline
- MDN: anchor-name
- MDN: :has()
- CSS-Tricks: The Gooey Effect (Lucas Bebber)
- DEV: Animated navbar inspired by Vercel (Ashirvad Bhushan)
- Motion: layout animations
- CSS Tip: Fancy hover effect with anchor positioning (Temani Afif)