Fullscreen Menu — Animated Nav Overlay HTML CSS JS

Fullscreen Menu · Modals · Plain HTML, CSS & JS · Live preview

Share & Support

What's included

Features

Clip-path circle reveal
The overlay wipes open from the button via an animated clip-path circle — GPU-friendly.
CSS custom-property stagger
Each link's --i index drives a calc() transition-delay, so they cascade in with no per-link JS.
Rise-into-view links
Links start translated down and clipped, then rise as they fade in.
Animated hamburger → X
Three bars morph into a close X via a class, switching colour over the dark overlay.
Scroll lock
Opening locks body scroll so the background can't move behind the overlay.
Multiple close paths
Escape, link click, and the toggle all close through one close() that restores scroll.
Accessible state
aria-expanded and aria-hidden update so the overlay is announced correctly.
Drop-in & no library
A complete nav overlay in plain HTML/CSS/JS — zero dependencies.

About this UI Snippet

Fullscreen Menu — Clip-Path Circle Reveal with Staggered Nav Links

Screenshot of the Fullscreen Menu snippet rendered live

A fullscreen menu is the bold navigation pattern where tapping the hamburger expands a full-viewport overlay of large links — common on agency, portfolio, and editorial sites. This snippet builds it in plain HTML, CSS, and vanilla JavaScript: a clip-path circle reveal from the menu button, links that stagger in, an animated hamburger-to-X, scroll lock, and the expected close behaviours — no library.

A circular clip-path reveal

Instead of a plain fade, the overlay reveals with an expanding circle: clip-path: circle(0% at …) anchored at the menu button's position grows to circle(150% …) on open, so the menu appears to spread out from the button the user tapped. Animating clip-path is GPU-friendly and far more distinctive than opacity alone — it's the signature "wipe open from the corner" effect, and anchoring the circle at the button ties the overlay's origin to the trigger.

Staggered link entrance

The nav links don't all appear at once. Each <li> carries a custom property --i (its index), and the open state translates each link up into place with a transition-delay of base + i × step — so they cascade in one after another. Driving the stagger with a CSS custom property and calc() means the delay is data-free CSS (no per-link JavaScript), and adding a link is just another <li> with the next index. The links start translated down and clipped by their overflow: hidden parent, so they rise into view like a reveal.

Hamburger that becomes an X

The toggle's three bars animate into a close X: the top and bottom bars translate to the centre and rotate ±45°, the middle fades out. This morph is pure CSS driven by an fm-on class, and the bars switch colour to stay visible against the dark overlay. A single toggle handler opens or closes based on the current state.

Scroll lock and accessible close

Opening sets body { overflow: hidden } so the page behind can't scroll — essential for a full-viewport overlay, or the background scrolls under the menu. The overlay closes on Escape, on choosing any link, and on the toggle, all routed through one close() that also restores scroll, resets the hamburger, and updates aria-expanded/aria-hidden so the state is announced to assistive tech.

Drop-in and adaptable

It's a complete navigation overlay — wire the links to your routes, restyle the type and colours, and adjust the clip-path origin to your button's position. It's a clear reference for clip-path reveals, CSS custom-property staggering, and the scroll-lock-and-close lifecycle every fullscreen menu needs.

Step by step

How to Use

  1. 1
    Paste HTML, CSS, and JSA header with a hamburger renders; the page sits behind a hidden fullscreen overlay.
  2. 2
    Open the menuClick the hamburger — the overlay wipes open in a circle from the button and links stagger in.
  3. 3
    Close itPress Escape, click the X, or choose a link; the overlay wipes closed and scroll unlocks.
  4. 4
    Wire your linksReplace the nav items with your routes; add an <li> with the next --i to extend.
  5. 5
    Adjust the originMatch the clip-path circle's "at" position to your menu button's location.
  6. 6
    Restyle itChange the overlay colour, link type size, and stagger timing to fit your brand.

Real-world uses

Common Use Cases

Agency and portfolio sites
A bold full-viewport nav — pair with a portfolio hero behind it.
Editorial and brand sites
Large-type navigation for a striking first impression, alongside a mega menu for content-heavy sites.
Mobile navigation
A full-screen menu is ideal on phones, next to a hamburger nav for simpler bars.
Landing and campaign pages
Minimal header that expands to full nav on demand.
Product and launch sites
A dramatic menu that matches a bold visual design.
Learning clip-path & stagger
A reference for clip-path reveals and CSS stagger — compare with a side drawer.

Got questions?

Frequently Asked Questions

The overlay has clip-path: circle(0% at <button position>) when closed, which clips it to nothing, and circle(150% at <same position>) when open, which expands the visible circle beyond the viewport. A CSS transition animates clip-path between the two, so the menu appears to wipe open from the button. Anchoring the circle's centre at the menu button ties the reveal's origin to the trigger.

Each <li> sets a CSS custom property --i to its index. The open state applies transition-delay: calc(base + var(--i) * step) to each link, so link 1 animates slightly before link 2, and so on — a cascade. Because the delay is computed in CSS from the index, there's no JavaScript timing per link; adding a link is just another <li> with the next --i value.

A fullscreen overlay covers the viewport, but without locking scroll the page behind it still scrolls when the user swipes or scrolls over the menu — which feels broken and can move the background out from under the links. Setting body { overflow: hidden } on open (and restoring it on close) freezes the page behind the overlay. close() always restores it so scroll never gets stuck off.

The toggle is a real button with aria-label and aria-expanded that flips on open/close, and the overlay's aria-hidden updates so assistive tech knows whether it's active. Escape closes it, matching keyboard convention. For full robustness you'd also trap focus within the open overlay and return focus to the toggle on close — a small addition on top of this foundation.

Hold an open boolean in state and toggle classes/aria from it; lock body scroll in an effect when open. In React use useState plus a useEffect for the Escape listener and scroll lock; in Vue, a ref with onMounted/onUnmounted; in Angular, a property with HostListener. The clip-path and stagger CSS are framework-agnostic — only the open state and listeners move into the framework.