Blog
Animated Border Navigation Menu with HTML and CSS
Create a navigation menu with a border that animates into view on hover, keyboard focus, or the current-page state. This effect uses HTML and CSS only, so it adds no JavaScript dependency.
Quick answer: Set each link to position: relative, draw its outline with a ::after pseudo-element, then transition its opacity and scale. Reveal it with :hover, :focus-visible, and a current-page class.
Use the live example below to try the interaction. The source ZIP contains a standalone HTML file, stylesheet, and README.
What you will build
This responsive navigation bar wraps on narrow screens. Hovering or focusing a link reveals a rounded border; the current page can keep its border visible. The example uses no JavaScript, external fonts, images, or build tools.
HTML for the animated navigation menu
Use a <nav> landmark with an accessible name. Each item is a regular link. Replace the sample fragment destinations with real page URLs. Mark the active destination with aria-current="page" so its state is not communicated by color alone.
CSS for the animated border effect
The ::after pseudo-element draws the border without extra markup. It starts transparent and slightly smaller, then transitions to full size and opacity on hover, keyboard focus, or the current-page state. The explicit focus outline keeps keyboard focus easy to see.
The links use flex-wrap to move onto another line on small screens. Adjust the spacing, radius, and colors to match your design. Keep the transition short and avoid fast repeating animation.
How the CSS animation works
- The link uses
position: relativeto contain its pseudo-element. - The pseudo-element fills the link and draws a border using the
--border-colorcustom property. - The hidden state uses
opacity: 0andscale(.88). - Hover, keyboard focus, or the active-page class changes opacity and scale.
- The CSS transition animates those changes. The visible label stays in the HTML.
Customize the navigation border
- Change colors: edit
--border-coloron a link or its:nth-child()selector. - Use square corners: reduce
border-radiuson the link. - Highlight the current page: add
is-currentandaria-current="page"to the matching link. - Adjust motion: change the transition duration and easing while keeping movement restrained.
Accessibility and reduced motion
Do not make hover the only way to reveal the border. The example also styles :focus-visible for keyboard users and keeps the link label readable. The stylesheet honors prefers-reduced-motion because the animation is decorative and can be reduced without hiding information. See MDN’s guides to :hover and prefers-reduced-motion.
Common issues
The border appears behind the text
Keep the link positioned and the pseudo-element behind its contents. isolation: isolate confines that stacking layer to the link.
The effect does not work with the keyboard
Add :focus-visible alongside :hover. Keep a visible focus outline and check whether theme styles remove it.
The border appears on every link
The demo keeps the current page selected with .is-current. Remove that class from other links and apply it only to the active page.
Frequently asked questions
Does an animated CSS border menu need JavaScript?
No. CSS transitions and pseudo-elements create the border effect. JavaScript is not needed for hover, focus, or current-page styling.
Does this navigation work on touch screens?
Yes. The menu items are regular links and do not rely on hover to reveal essential information. The border is decorative.
Can I use the effect on buttons or cards?
Yes. Apply the positioned-element and pseudo-element pattern, then provide clear hover and keyboard-focus states for interactive controls.
How do I select the highlighted menu item?
Add .is-current and aria-current="page" to the link for the page being viewed. A server-rendered site can set these attributes from the current route.
Download the source code
Download the ZIP, extract the files into one folder, and open index.html in a browser. Replace the sample link destinations and labels before using the navigation on a live site.
References
CSS HOVER EFFECT
Animated border navigation
Hover over a link or use Tab and Shift+Tab to see its border animate.
Try moving keyboard focus between the links.
<nav class="demo-nav" aria-label="Demo navigation">
<a class="nav-link is-current" href="#home" aria-current="page">Home</a>
<a class="nav-link" href="#about">About</a>
<a class="nav-link" href="#services">Services</a>
<a class="nav-link" href="#projects">Projects</a>
<a class="nav-link" href="#contact">Contact</a>
</nav>
.demo-nav {
display: flex;
flex-wrap: wrap;
justify-content: center;
gap: 10px;
padding: 14px;
border: 1px solid #e3e9f4;
border-radius: 18px;
background: #f8faff;
}
.nav-link {
--border-color: #315cc9;
position: relative;
isolation: isolate;
display: inline-flex;
min-height: 48px;
align-items: center;
justify-content: center;
padding: 0 18px;
border-radius: 10px;
color: #263650;
font-weight: 700;
text-decoration: none;
}
.nav-link::after {
position: absolute;
z-index: -1;
inset: 0;
border: 2px solid var(--border-color);
border-radius: inherit;
content: "";
opacity: 0;
transform: scale(.88);
transition: opacity .22s ease, transform .22s ease;
}
.nav-link:hover,
.nav-link:focus-visible,
.nav-link.is-current {
color: #244db4;
background: #eaf0ff;
}
.nav-link:hover::after,
.nav-link:focus-visible::after,
.nav-link.is-current::after {
opacity: 1;
transform: scale(1);
}
.nav-link:nth-child(2) { --border-color: #7c4dce; }
.nav-link:nth-child(3) { --border-color: #e06b55; }
.nav-link:nth-child(4) { --border-color: #138b8b; }
.nav-link:nth-child(5) { --border-color: #d24f91; }
.nav-link:focus-visible {
outline: 3px solid #17233c;
outline-offset: 4px;
}
@media (prefers-reduced-motion: reduce) {
*, *::before, *::after {
transition-duration: .01ms !important;
}
}