09 / 20
All 20 in 20 CSS Mega Menus
- 01Mega Menu Reference Build with Focus Within
- 02Hover Intent Delay to Stop Panel Flicker
- 03The Safe Triangle Diagonal Pointer Problem
- 04Mega Menu Column Layout with CSS Grid
- 05Panel Positioning and Viewport Edge Collision
- 06Full Bleed Panel Inside a Constrained Header
- 07Keyboard Accessible Mega Menu with Escape
- 08Arrow Key Navigation Across Menu Columns
- 09ARIA for Disclosure Style Navigation Panels
- 10Mega Menu Touch and Double Tap Behavior
- 11Screen Reader Announcements on Panel Open
- 12Shared Panel That Swaps Content Between Items
- 13Mega Menu Entry Transition with Starting Style
- 14How a Mega Menu Should Collapse on Mobile
- 15Editorial Mega Menu with Featured Image
- 16Dashboard Mega Menu with Live Status Panel
- 17Mega Menu with Category Image Cards
- 18Department Store Mega Menu Grid
- 19Product Finder Mega Menu with Filters
- 20Promotional Mega Menu with Offer Panel
ARIA for Disclosure Style Navigation Panels
The boundary marker for the whole collection, shipped as a working retail header. role="menu" and role="menuitem" belong to application menus and bring keyboard conventions that are wrong for navigation links. This panel is a disclosure instead: a <button> with aria-expanded and aria-controls, a named region, real lists, real links and aria-current="page" on the active one.
Nucleo: 44,000+ SVG icons in five families · All Icons Bundle $149
Nucleo · Affiliate link
The code
<section class="mm-09" aria-labelledby="mm-09-title">
<h2 class="mm-09__sr" id="mm-09-title">Aperture</h2>
<div class="mm-09__theme">
<input class="mm-09__theme-input" type="checkbox" id="mm-09-theme">
<label class="mm-09__theme-label" for="mm-09-theme">
<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false"><circle cx="12" cy="12" r="8.5" fill="none" stroke="currentColor" stroke-width="1.6"/><path d="M12 3.5a8.5 8.5 0 0 0 0 17Z" fill="currentColor"/></svg>
<span class="mm-09__sr">Toggle dark theme</span>
</label>
</div>
<header class="mm-09__header">
<div class="mm-09__bar">
<a class="mm-09__brand" href="#mm-09-title">
<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false"><circle cx="12" cy="12" r="8.5" fill="none" stroke="currentColor" stroke-width="1.7"/><path d="M12 3.5 16 11h-8Zm8.2 5.6L16 16l4.2 1.1ZM3.8 9.1 8 16l-4.2 1.1Z" fill="currentColor"/></svg>
APERTURE
</a>
<nav class="mm-09__nav" aria-label="Primary">
<ul class="mm-09__list">
<li class="mm-09__item">
<button class="mm-09__trigger" type="button" id="mm-09-trigger-products" aria-expanded="false" aria-controls="mm-09-panel-products">Products</button>
<div class="mm-09__panel" id="mm-09-panel-products" aria-labelledby="mm-09-trigger-products">
<div class="mm-09__panel-inner">
<section class="mm-09__col" aria-labelledby="mm-09-h-bodies">
<h3 class="mm-09__col-head" id="mm-09-h-bodies">Bodies</h3>
<ul class="mm-09__links">
<li><a href="#mm-09-title">Full frame</a></li>
<li><a href="#mm-09-title">APS-C</a></li>
<li><a href="#mm-09-title">Medium format</a></li>
<li><a href="#mm-09-title">Rangefinder</a></li>
</ul>
</section>
<section class="mm-09__col" aria-labelledby="mm-09-h-glass">
<h3 class="mm-09__col-head" id="mm-09-h-glass">Lenses</h3>
<ul class="mm-09__links">
<li><a href="#mm-09-title" aria-current="page">Primes</a></li>
<li><a href="#mm-09-title">Zooms</a></li>
<li><a href="#mm-09-title">Tilt-shift</a></li>
<li><a href="#mm-09-title">Adapters</a></li>
</ul>
</section>
<section class="mm-09__col" aria-labelledby="mm-09-h-light">
<h3 class="mm-09__col-head" id="mm-09-h-light">Lighting</h3>
<ul class="mm-09__links">
<li><a href="#mm-09-title">Strobes</a></li>
<li><a href="#mm-09-title">Continuous</a></li>
<li><a href="#mm-09-title">Modifiers</a></li>
</ul>
</section>
<dl class="mm-09__spec">
<div><dt>In stock today</dt><dd>412 items</dd></div>
<div><dt>Trade-in</dt><dd>Valuation in 24h</dd></div>
<div><dt>Rental</dt><dd>Next-day to 42 cities</dd></div>
</dl>
</div>
</div>
</li>
<li class="mm-09__item">
<button class="mm-09__trigger" type="button" id="mm-09-trigger-service" aria-expanded="false" aria-controls="mm-09-panel-service">Service</button>
<div class="mm-09__panel" id="mm-09-panel-service" aria-labelledby="mm-09-trigger-service">
<div class="mm-09__panel-inner">
<section class="mm-09__col" aria-labelledby="mm-09-h-repair">
<h3 class="mm-09__col-head" id="mm-09-h-repair">Repair</h3>
<ul class="mm-09__links"><li><a href="#mm-09-title">Sensor clean</a></li><li><a href="#mm-09-title">Shutter replacement</a></li><li><a href="#mm-09-title">Lens calibration</a></li></ul>
</section>
<section class="mm-09__col" aria-labelledby="mm-09-h-trade">
<h3 class="mm-09__col-head" id="mm-09-h-trade">Trade</h3>
<ul class="mm-09__links"><li><a href="#mm-09-title">Sell your kit</a></li><li><a href="#mm-09-title">Part exchange</a></li></ul>
</section>
<section class="mm-09__col" aria-labelledby="mm-09-h-learn9">
<h3 class="mm-09__col-head" id="mm-09-h-learn9">Learn</h3>
<ul class="mm-09__links"><li><a href="#mm-09-title">Workshops</a></li><li><a href="#mm-09-title">Darkroom hire</a></li></ul>
</section>
<dl class="mm-09__spec">
<div><dt>Turnaround</dt><dd>5 working days</dd></div>
<div><dt>Warranty</dt><dd>12 months on repairs</dd></div>
</dl>
</div>
</div>
</li>
<li class="mm-09__item"><a class="mm-09__plain" href="#mm-09-title">Used</a></li>
<li class="mm-09__item"><a class="mm-09__plain mm-09__plain--flag" href="#mm-09-title">Clearance</a></li>
</ul>
</nav>
<div class="mm-09__utils">
<a class="mm-09__util" href="#mm-09-title">Stores</a>
<a class="mm-09__util" href="#mm-09-title">Account</a>
<a class="mm-09__bag" href="#mm-09-title">Bag (1)</a>
</div>
</div>
</header>
<main class="mm-09__page">
<div class="mm-09__feature">
<p class="mm-09__feature-k">Primes / 35mm</p>
<h1 class="mm-09__feature-h">Aperture 35mm f/1.4 Mark III</h1>
<p class="mm-09__feature-p">Eleven elements, weather sealed, 420g. Built for the frame you did not plan for.</p>
<p class="mm-09__price">£1,290 <span>or £107/mo</span></p>
</div>
</main>
</section><section class="mm-09" aria-labelledby="mm-09-title">
<h2 class="mm-09__sr" id="mm-09-title">Aperture</h2>
<div class="mm-09__theme">
<input class="mm-09__theme-input" type="checkbox" id="mm-09-theme">
<label class="mm-09__theme-label" for="mm-09-theme">
<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false"><circle cx="12" cy="12" r="8.5" fill="none" stroke="currentColor" stroke-width="1.6"/><path d="M12 3.5a8.5 8.5 0 0 0 0 17Z" fill="currentColor"/></svg>
<span class="mm-09__sr">Toggle dark theme</span>
</label>
</div>
<header class="mm-09__header">
<div class="mm-09__bar">
<a class="mm-09__brand" href="#mm-09-title">
<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false"><circle cx="12" cy="12" r="8.5" fill="none" stroke="currentColor" stroke-width="1.7"/><path d="M12 3.5 16 11h-8Zm8.2 5.6L16 16l4.2 1.1ZM3.8 9.1 8 16l-4.2 1.1Z" fill="currentColor"/></svg>
APERTURE
</a>
<nav class="mm-09__nav" aria-label="Primary">
<ul class="mm-09__list">
<li class="mm-09__item">
<button class="mm-09__trigger" type="button" id="mm-09-trigger-products" aria-expanded="false" aria-controls="mm-09-panel-products">Products</button>
<div class="mm-09__panel" id="mm-09-panel-products" aria-labelledby="mm-09-trigger-products">
<div class="mm-09__panel-inner">
<section class="mm-09__col" aria-labelledby="mm-09-h-bodies">
<h3 class="mm-09__col-head" id="mm-09-h-bodies">Bodies</h3>
<ul class="mm-09__links">
<li><a href="#mm-09-title">Full frame</a></li>
<li><a href="#mm-09-title">APS-C</a></li>
<li><a href="#mm-09-title">Medium format</a></li>
<li><a href="#mm-09-title">Rangefinder</a></li>
</ul>
</section>
<section class="mm-09__col" aria-labelledby="mm-09-h-glass">
<h3 class="mm-09__col-head" id="mm-09-h-glass">Lenses</h3>
<ul class="mm-09__links">
<li><a href="#mm-09-title" aria-current="page">Primes</a></li>
<li><a href="#mm-09-title">Zooms</a></li>
<li><a href="#mm-09-title">Tilt-shift</a></li>
<li><a href="#mm-09-title">Adapters</a></li>
</ul>
</section>
<section class="mm-09__col" aria-labelledby="mm-09-h-light">
<h3 class="mm-09__col-head" id="mm-09-h-light">Lighting</h3>
<ul class="mm-09__links">
<li><a href="#mm-09-title">Strobes</a></li>
<li><a href="#mm-09-title">Continuous</a></li>
<li><a href="#mm-09-title">Modifiers</a></li>
</ul>
</section>
<dl class="mm-09__spec">
<div><dt>In stock today</dt><dd>412 items</dd></div>
<div><dt>Trade-in</dt><dd>Valuation in 24h</dd></div>
<div><dt>Rental</dt><dd>Next-day to 42 cities</dd></div>
</dl>
</div>
</div>
</li>
<li class="mm-09__item">
<button class="mm-09__trigger" type="button" id="mm-09-trigger-service" aria-expanded="false" aria-controls="mm-09-panel-service">Service</button>
<div class="mm-09__panel" id="mm-09-panel-service" aria-labelledby="mm-09-trigger-service">
<div class="mm-09__panel-inner">
<section class="mm-09__col" aria-labelledby="mm-09-h-repair">
<h3 class="mm-09__col-head" id="mm-09-h-repair">Repair</h3>
<ul class="mm-09__links"><li><a href="#mm-09-title">Sensor clean</a></li><li><a href="#mm-09-title">Shutter replacement</a></li><li><a href="#mm-09-title">Lens calibration</a></li></ul>
</section>
<section class="mm-09__col" aria-labelledby="mm-09-h-trade">
<h3 class="mm-09__col-head" id="mm-09-h-trade">Trade</h3>
<ul class="mm-09__links"><li><a href="#mm-09-title">Sell your kit</a></li><li><a href="#mm-09-title">Part exchange</a></li></ul>
</section>
<section class="mm-09__col" aria-labelledby="mm-09-h-learn9">
<h3 class="mm-09__col-head" id="mm-09-h-learn9">Learn</h3>
<ul class="mm-09__links"><li><a href="#mm-09-title">Workshops</a></li><li><a href="#mm-09-title">Darkroom hire</a></li></ul>
</section>
<dl class="mm-09__spec">
<div><dt>Turnaround</dt><dd>5 working days</dd></div>
<div><dt>Warranty</dt><dd>12 months on repairs</dd></div>
</dl>
</div>
</div>
</li>
<li class="mm-09__item"><a class="mm-09__plain" href="#mm-09-title">Used</a></li>
<li class="mm-09__item"><a class="mm-09__plain mm-09__plain--flag" href="#mm-09-title">Clearance</a></li>
</ul>
</nav>
<div class="mm-09__utils">
<a class="mm-09__util" href="#mm-09-title">Stores</a>
<a class="mm-09__util" href="#mm-09-title">Account</a>
<a class="mm-09__bag" href="#mm-09-title">Bag (1)</a>
</div>
</div>
</header>
<main class="mm-09__page">
<div class="mm-09__feature">
<p class="mm-09__feature-k">Primes / 35mm</p>
<h1 class="mm-09__feature-h">Aperture 35mm f/1.4 Mark III</h1>
<p class="mm-09__feature-p">Eleven elements, weather sealed, 420g. Built for the frame you did not plan for.</p>
<p class="mm-09__price">£1,290 <span>or £107/mo</span></p>
</div>
</main>
</section>.mm-09 {
--mm-09-bg: #ffffff;
--mm-09-surf: #ffffff;
--mm-09-line: #111111;
--mm-09-soft: #ededed;
--mm-09-ink: #111111;
--mm-09-mut: #6b6b6b;
--mm-09-red: #d90429;
--mm-09-red: oklch(55% 0.23 25);
--mm-09-rule: 1px;
--mm-09-font-display: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
width: 100%;
min-height: 100vh;
min-height: 100svh;
display: block;
position: relative;
box-sizing: border-box;
background: var(--mm-09-bg);
color: var(--mm-09-ink);
font-family: system-ui, -apple-system, "Segoe UI", sans-serif;
line-height: 1.55;
}
.mm-09 *,
.mm-09 *::before,
.mm-09 *::after {
box-sizing: border-box;
}
.mm-09 :focus-visible {
outline: 2px solid var(--mm-09-red);
outline-offset: 2px;
}
.mm-09__sr {
position: absolute;
width: 1px;
height: 1px;
margin: -1px;
padding: 0;
overflow: hidden;
clip-path: inset(50%);
white-space: nowrap;
border: 0;
}
.mm-09:has(.mm-09__theme-input:checked) {
--mm-09-bg: #0b0b0b;
--mm-09-surf: #131313;
--mm-09-line: #f2f2f2;
--mm-09-soft: #262626;
--mm-09-ink: #f2f2f2;
--mm-09-mut: #a0a0a0;
--mm-09-red: #ff4d6d;
--mm-09-red: oklch(71% 0.18 20);
}
@media (prefers-color-scheme: dark) {
.mm-09 {
--mm-09-bg: #0b0b0b;
--mm-09-surf: #131313;
--mm-09-line: #f2f2f2;
--mm-09-soft: #262626;
--mm-09-ink: #f2f2f2;
--mm-09-mut: #a0a0a0;
--mm-09-red: #ff4d6d;
--mm-09-red: oklch(71% 0.18 20);
}
.mm-09:has(.mm-09__theme-input:checked) {
--mm-09-bg: #ffffff;
--mm-09-surf: #ffffff;
--mm-09-line: #111111;
--mm-09-soft: #ededed;
--mm-09-ink: #111111;
--mm-09-mut: #6b6b6b;
--mm-09-red: #d90429;
--mm-09-red: oklch(55% 0.23 25);
}
}
@media (prefers-color-scheme: light) {
.mm-09:has(.mm-09__theme-input:checked) {
--mm-09-bg: #0b0b0b;
--mm-09-surf: #131313;
--mm-09-line: #f2f2f2;
--mm-09-soft: #262626;
--mm-09-ink: #f2f2f2;
--mm-09-mut: #a0a0a0;
--mm-09-red: #ff4d6d;
--mm-09-red: oklch(71% 0.18 20);
}
}
.mm-09__theme {
position: absolute;
inset-block-start: 12px;
inset-inline-end: clamp(0.75rem, 3vw, 1.5rem);
z-index: 60;
}
.mm-09__theme-input {
position: absolute;
opacity: 0;
inline-size: 100%;
block-size: 100%;
margin: 0;
cursor: pointer;
}
.mm-09__theme-label {
display: grid;
place-items: center;
inline-size: 44px;
block-size: 44px;
border: var(--mm-09-rule) solid var(--mm-09-line);
background: var(--mm-09-surf);
color: var(--mm-09-ink);
cursor: pointer;
}
.mm-09__theme-label svg {
inline-size: 20px;
block-size: 20px;
}
.mm-09__theme-input:focus-visible + .mm-09__theme-label {
outline: 2px solid var(--mm-09-red);
outline-offset: 3px;
}
.mm-09__header {
position: relative;
z-index: 10;
inline-size: 100%;
border-block-end: 2px solid var(--mm-09-line);
background: var(--mm-09-surf);
}
.mm-09__bar {
inline-size: min(80rem, calc(100% - 2rem));
margin-inline: auto;
display: flex;
align-items: center;
gap: clamp(0.75rem, 3vw, 2.5rem);
flex-wrap: wrap;
min-block-size: 66px;
padding-inline-end: 60px;
}
.mm-09__brand {
display: inline-flex;
align-items: center;
gap: 0.5rem;
color: var(--mm-09-ink);
text-decoration: none;
font: 700 0.95rem/1 var(--mm-09-font-display);
letter-spacing: 0.22em;
}
.mm-09__brand svg {
inline-size: 22px;
block-size: 22px;
}
.mm-09__nav {
min-inline-size: 0;
}
.mm-09__list {
display: flex;
flex-wrap: wrap;
gap: clamp(0.15rem, 1.5vw, 0.5rem);
list-style: none;
margin: 0;
padding: 0;
min-inline-size: 0;
}
.mm-09__item {
position: static;
}
.mm-09__trigger,
.mm-09__plain {
display: inline-flex;
align-items: center;
min-block-size: 44px;
padding-inline: 0.6rem;
border: 0;
background: transparent;
color: var(--mm-09-ink);
font: 600 0.82rem/1 var(--mm-09-font-display);
letter-spacing: 0.14em;
text-transform: uppercase;
text-decoration: none;
cursor: pointer;
}
.mm-09__item--open > .mm-09__trigger,
.mm-09__item:hover > .mm-09__trigger,
.mm-09__item:focus-within > .mm-09__trigger {
background: var(--mm-09-ink);
color: var(--mm-09-bg);
}
.mm-09__plain--flag {
color: var(--mm-09-red);
}
.mm-09__utils {
margin-inline-start: auto;
display: flex;
align-items: center;
gap: 0.9rem;
}
.mm-09__util {
color: var(--mm-09-mut);
text-decoration: none;
font: 500 0.78rem/1 var(--mm-09-font-display);
letter-spacing: 0.1em;
text-transform: uppercase;
display: inline-flex;
align-items: center;
min-block-size: 44px;
}
.mm-09__bag {
display: inline-flex;
align-items: center;
min-block-size: 34px;
padding-inline: 0.7rem;
border: var(--mm-09-rule) solid var(--mm-09-line);
color: var(--mm-09-ink);
text-decoration: none;
font: 600 0.75rem/1 var(--mm-09-font-display);
letter-spacing: 0.1em;
text-transform: uppercase;
}
.mm-09__panel {
position: absolute;
inset-inline: 0;
inset-block-start: 100%;
z-index: 30;
background: var(--mm-09-surf);
border-block-end: 2px solid var(--mm-09-line);
opacity: 0;
visibility: hidden;
pointer-events: none;
transition: opacity 150ms ease, visibility 0s linear 150ms;
}
.mm-09__item--open > .mm-09__panel,
.mm-09__item:focus-within > .mm-09__panel {
opacity: 1;
visibility: visible;
pointer-events: auto;
transition-delay: 0s;
}
@media (hover: hover) {
.mm-09__item:hover > .mm-09__panel {
opacity: 1;
visibility: visible;
pointer-events: auto;
transition-delay: 0s;
}
}
.mm-09__panel-inner {
inline-size: min(80rem, calc(100% - 2rem));
margin-inline: auto;
display: grid;
grid-template-columns: repeat(auto-fit, minmax(min(100%, 11rem), 1fr));
gap: 0 clamp(1rem, 4vw, 3rem);
padding-block: clamp(1.1rem, 3vw, 1.9rem);
}
.mm-09__col {
min-inline-size: 0;
}
.mm-09__col-head {
margin: 0 0 0.4rem;
padding-block-end: 0.35rem;
border-block-end: 2px solid var(--mm-09-line);
font: 700 0.7rem/1 var(--mm-09-font-display);
letter-spacing: 0.18em;
text-transform: uppercase;
}
.mm-09__links {
list-style: none;
margin: 0;
padding: 0;
display: grid;
}
.mm-09__links a {
display: flex;
align-items: center;
min-block-size: 44px;
color: var(--mm-09-ink);
text-decoration: none;
font-size: 0.9rem;
border-block-end: var(--mm-09-rule) solid var(--mm-09-soft);
min-inline-size: 0;
}
.mm-09__links a:hover {
color: var(--mm-09-red);
}
.mm-09__links a[aria-current="page"] {
font-weight: 700;
box-shadow: inset 3px 0 0 var(--mm-09-red);
padding-inline-start: 0.5rem;
}
.mm-09__spec {
display: grid;
align-content: start;
gap: 0.6rem;
margin: 0;
padding: 0.9rem 1rem;
background: var(--mm-09-soft);
min-inline-size: 0;
}
.mm-09__spec dt {
font: 700 0.62rem/1 var(--mm-09-font-display);
letter-spacing: 0.16em;
text-transform: uppercase;
color: var(--mm-09-mut);
}
.mm-09__spec dd {
margin: 0.15rem 0 0;
font-size: 0.86rem;
}
.mm-09__page {
inline-size: min(80rem, calc(100% - 2rem));
margin-inline: auto;
padding-block: clamp(2.5rem, 8vw, 5rem);
}
.mm-09__feature {
max-inline-size: 40rem;
display: grid;
gap: 0.5rem;
}
.mm-09__feature-k {
margin: 0;
font: 600 0.72rem/1 var(--mm-09-font-display);
letter-spacing: 0.2em;
text-transform: uppercase;
color: var(--mm-09-red);
}
.mm-09__feature-h {
margin: 0;
font: 400 clamp(1.9rem, 6vw, 3.2rem)/1.05 var(--mm-09-font-display);
letter-spacing: -0.04em;
text-wrap: balance;
}
.mm-09__feature-p {
margin: 0;
color: var(--mm-09-mut);
font-size: clamp(0.95rem, 2.3vw, 1.05rem);
text-wrap: pretty;
}
.mm-09__price {
margin: 0.4rem 0 0;
font: 700 1.6rem/1 var(--mm-09-font-display);
font-variant-numeric: tabular-nums;
}
.mm-09__price span {
font: 400 0.85rem/1 var(--mm-09-font-display);
color: var(--mm-09-mut);
}
@media (max-width: 52rem) {
.mm-09__bar {
flex-direction: column;
align-items: stretch;
padding-block: 0.6rem;
}
.mm-09__list {
flex-direction: column;
}
.mm-09__utils {
margin-inline-start: 0;
}
.mm-09__panel {
position: static;
opacity: 1;
visibility: visible;
pointer-events: auto;
display: none;
}
.mm-09__item--open > .mm-09__panel,
.mm-09__item:focus-within > .mm-09__panel {
display: block;
}
.mm-09__panel-inner {
inline-size: 100%;
}
}
@media (prefers-reduced-motion: reduce) {
.mm-09__panel {
transition-duration: 1ms;
}
}
@media (hover: hover) and (pointer: fine) {
.mm-09__trigger {
position: relative;
}
.mm-09__item:hover > .mm-09__trigger::after,
.mm-09__item:focus-within > .mm-09__trigger::after {
content: "";
position: absolute;
inset-inline: 0;
inset-block-start: 100%;
block-size: 16px;
}
}
/* Entry signature — rows switch on staccato with no fade, then the feature block glides up */
.mm-09__links li {
opacity: 0;
transition: opacity 1ms steps(1, end);
}
.mm-09__item:hover > .mm-09__panel .mm-09__links li,
.mm-09__item:focus-within > .mm-09__panel .mm-09__links li,
.mm-09__item--open > .mm-09__panel .mm-09__links li {
opacity: 1;
}
.mm-09__links li:nth-child(1) {
transition-delay: 30ms;
}
.mm-09__links li:nth-child(2) {
transition-delay: 80ms;
}
.mm-09__links li:nth-child(3) {
transition-delay: 130ms;
}
.mm-09__links li:nth-child(4) {
transition-delay: 180ms;
}
.mm-09__links li:nth-child(5) {
transition-delay: 230ms;
}
.mm-09__links li:nth-child(6) {
transition-delay: 280ms;
}
.mm-09__links li:nth-child(n+7) {
transition-delay: 280ms;
}
.mm-09__feature {
opacity: 0;
translate: 0 10px;
transition: opacity 260ms ease 240ms, translate 340ms cubic-bezier(0.22, 1, 0.36, 1) 240ms;
}
.mm-09__item:hover > .mm-09__panel .mm-09__feature,
.mm-09__item:focus-within > .mm-09__panel .mm-09__feature,
.mm-09__item--open > .mm-09__panel .mm-09__feature {
opacity: 1;
translate: 0 0;
}
@media (prefers-reduced-motion: reduce) {
.mm-09__links li,
.mm-09__feature {
transition-duration: 1ms;
transition-delay: 0s;
animation: none;
}
.mm-09__links li {
opacity: 1;
}
.mm-09__feature {
opacity: 1;
translate: none;
}
}.mm-09 {
--mm-09-bg: #ffffff;
--mm-09-surf: #ffffff;
--mm-09-line: #111111;
--mm-09-soft: #ededed;
--mm-09-ink: #111111;
--mm-09-mut: #6b6b6b;
--mm-09-red: #d90429;
--mm-09-red: oklch(55% 0.23 25);
--mm-09-rule: 1px;
--mm-09-font-display: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
width: 100%;
min-height: 100vh;
min-height: 100svh;
display: block;
position: relative;
box-sizing: border-box;
background: var(--mm-09-bg);
color: var(--mm-09-ink);
font-family: system-ui, -apple-system, "Segoe UI", sans-serif;
line-height: 1.55;
}
.mm-09 *,
.mm-09 *::before,
.mm-09 *::after {
box-sizing: border-box;
}
.mm-09 :focus-visible {
outline: 2px solid var(--mm-09-red);
outline-offset: 2px;
}
.mm-09__sr {
position: absolute;
width: 1px;
height: 1px;
margin: -1px;
padding: 0;
overflow: hidden;
clip-path: inset(50%);
white-space: nowrap;
border: 0;
}
.mm-09:has(.mm-09__theme-input:checked) {
--mm-09-bg: #0b0b0b;
--mm-09-surf: #131313;
--mm-09-line: #f2f2f2;
--mm-09-soft: #262626;
--mm-09-ink: #f2f2f2;
--mm-09-mut: #a0a0a0;
--mm-09-red: #ff4d6d;
--mm-09-red: oklch(71% 0.18 20);
}
@media (prefers-color-scheme: dark) {
.mm-09 {
--mm-09-bg: #0b0b0b;
--mm-09-surf: #131313;
--mm-09-line: #f2f2f2;
--mm-09-soft: #262626;
--mm-09-ink: #f2f2f2;
--mm-09-mut: #a0a0a0;
--mm-09-red: #ff4d6d;
--mm-09-red: oklch(71% 0.18 20);
}
.mm-09:has(.mm-09__theme-input:checked) {
--mm-09-bg: #ffffff;
--mm-09-surf: #ffffff;
--mm-09-line: #111111;
--mm-09-soft: #ededed;
--mm-09-ink: #111111;
--mm-09-mut: #6b6b6b;
--mm-09-red: #d90429;
--mm-09-red: oklch(55% 0.23 25);
}
}
@media (prefers-color-scheme: light) {
.mm-09:has(.mm-09__theme-input:checked) {
--mm-09-bg: #0b0b0b;
--mm-09-surf: #131313;
--mm-09-line: #f2f2f2;
--mm-09-soft: #262626;
--mm-09-ink: #f2f2f2;
--mm-09-mut: #a0a0a0;
--mm-09-red: #ff4d6d;
--mm-09-red: oklch(71% 0.18 20);
}
}
.mm-09__theme {
position: absolute;
inset-block-start: 12px;
inset-inline-end: clamp(0.75rem, 3vw, 1.5rem);
z-index: 60;
}
.mm-09__theme-input {
position: absolute;
opacity: 0;
inline-size: 100%;
block-size: 100%;
margin: 0;
cursor: pointer;
}
.mm-09__theme-label {
display: grid;
place-items: center;
inline-size: 44px;
block-size: 44px;
border: var(--mm-09-rule) solid var(--mm-09-line);
background: var(--mm-09-surf);
color: var(--mm-09-ink);
cursor: pointer;
}
.mm-09__theme-label svg {
inline-size: 20px;
block-size: 20px;
}
.mm-09__theme-input:focus-visible + .mm-09__theme-label {
outline: 2px solid var(--mm-09-red);
outline-offset: 3px;
}
.mm-09__header {
position: relative;
z-index: 10;
inline-size: 100%;
border-block-end: 2px solid var(--mm-09-line);
background: var(--mm-09-surf);
}
.mm-09__bar {
inline-size: min(80rem, calc(100% - 2rem));
margin-inline: auto;
display: flex;
align-items: center;
gap: clamp(0.75rem, 3vw, 2.5rem);
flex-wrap: wrap;
min-block-size: 66px;
padding-inline-end: 60px;
}
.mm-09__brand {
display: inline-flex;
align-items: center;
gap: 0.5rem;
color: var(--mm-09-ink);
text-decoration: none;
font: 700 0.95rem/1 var(--mm-09-font-display);
letter-spacing: 0.22em;
}
.mm-09__brand svg {
inline-size: 22px;
block-size: 22px;
}
.mm-09__nav {
min-inline-size: 0;
}
.mm-09__list {
display: flex;
flex-wrap: wrap;
gap: clamp(0.15rem, 1.5vw, 0.5rem);
list-style: none;
margin: 0;
padding: 0;
min-inline-size: 0;
}
.mm-09__item {
position: static;
}
.mm-09__trigger,
.mm-09__plain {
display: inline-flex;
align-items: center;
min-block-size: 44px;
padding-inline: 0.6rem;
border: 0;
background: transparent;
color: var(--mm-09-ink);
font: 600 0.82rem/1 var(--mm-09-font-display);
letter-spacing: 0.14em;
text-transform: uppercase;
text-decoration: none;
cursor: pointer;
}
.mm-09__item--open > .mm-09__trigger,
.mm-09__item:hover > .mm-09__trigger,
.mm-09__item:focus-within > .mm-09__trigger {
background: var(--mm-09-ink);
color: var(--mm-09-bg);
}
.mm-09__plain--flag {
color: var(--mm-09-red);
}
.mm-09__utils {
margin-inline-start: auto;
display: flex;
align-items: center;
gap: 0.9rem;
}
.mm-09__util {
color: var(--mm-09-mut);
text-decoration: none;
font: 500 0.78rem/1 var(--mm-09-font-display);
letter-spacing: 0.1em;
text-transform: uppercase;
display: inline-flex;
align-items: center;
min-block-size: 44px;
}
.mm-09__bag {
display: inline-flex;
align-items: center;
min-block-size: 34px;
padding-inline: 0.7rem;
border: var(--mm-09-rule) solid var(--mm-09-line);
color: var(--mm-09-ink);
text-decoration: none;
font: 600 0.75rem/1 var(--mm-09-font-display);
letter-spacing: 0.1em;
text-transform: uppercase;
}
.mm-09__panel {
position: absolute;
inset-inline: 0;
inset-block-start: 100%;
z-index: 30;
background: var(--mm-09-surf);
border-block-end: 2px solid var(--mm-09-line);
opacity: 0;
visibility: hidden;
pointer-events: none;
transition: opacity 150ms ease, visibility 0s linear 150ms;
}
.mm-09__item--open > .mm-09__panel,
.mm-09__item:focus-within > .mm-09__panel {
opacity: 1;
visibility: visible;
pointer-events: auto;
transition-delay: 0s;
}
@media (hover: hover) {
.mm-09__item:hover > .mm-09__panel {
opacity: 1;
visibility: visible;
pointer-events: auto;
transition-delay: 0s;
}
}
.mm-09__panel-inner {
inline-size: min(80rem, calc(100% - 2rem));
margin-inline: auto;
display: grid;
grid-template-columns: repeat(auto-fit, minmax(min(100%, 11rem), 1fr));
gap: 0 clamp(1rem, 4vw, 3rem);
padding-block: clamp(1.1rem, 3vw, 1.9rem);
}
.mm-09__col {
min-inline-size: 0;
}
.mm-09__col-head {
margin: 0 0 0.4rem;
padding-block-end: 0.35rem;
border-block-end: 2px solid var(--mm-09-line);
font: 700 0.7rem/1 var(--mm-09-font-display);
letter-spacing: 0.18em;
text-transform: uppercase;
}
.mm-09__links {
list-style: none;
margin: 0;
padding: 0;
display: grid;
}
.mm-09__links a {
display: flex;
align-items: center;
min-block-size: 44px;
color: var(--mm-09-ink);
text-decoration: none;
font-size: 0.9rem;
border-block-end: var(--mm-09-rule) solid var(--mm-09-soft);
min-inline-size: 0;
}
.mm-09__links a:hover {
color: var(--mm-09-red);
}
.mm-09__links a[aria-current="page"] {
font-weight: 700;
box-shadow: inset 3px 0 0 var(--mm-09-red);
padding-inline-start: 0.5rem;
}
.mm-09__spec {
display: grid;
align-content: start;
gap: 0.6rem;
margin: 0;
padding: 0.9rem 1rem;
background: var(--mm-09-soft);
min-inline-size: 0;
}
.mm-09__spec dt {
font: 700 0.62rem/1 var(--mm-09-font-display);
letter-spacing: 0.16em;
text-transform: uppercase;
color: var(--mm-09-mut);
}
.mm-09__spec dd {
margin: 0.15rem 0 0;
font-size: 0.86rem;
}
.mm-09__page {
inline-size: min(80rem, calc(100% - 2rem));
margin-inline: auto;
padding-block: clamp(2.5rem, 8vw, 5rem);
}
.mm-09__feature {
max-inline-size: 40rem;
display: grid;
gap: 0.5rem;
}
.mm-09__feature-k {
margin: 0;
font: 600 0.72rem/1 var(--mm-09-font-display);
letter-spacing: 0.2em;
text-transform: uppercase;
color: var(--mm-09-red);
}
.mm-09__feature-h {
margin: 0;
font: 400 clamp(1.9rem, 6vw, 3.2rem)/1.05 var(--mm-09-font-display);
letter-spacing: -0.04em;
text-wrap: balance;
}
.mm-09__feature-p {
margin: 0;
color: var(--mm-09-mut);
font-size: clamp(0.95rem, 2.3vw, 1.05rem);
text-wrap: pretty;
}
.mm-09__price {
margin: 0.4rem 0 0;
font: 700 1.6rem/1 var(--mm-09-font-display);
font-variant-numeric: tabular-nums;
}
.mm-09__price span {
font: 400 0.85rem/1 var(--mm-09-font-display);
color: var(--mm-09-mut);
}
@media (max-width: 52rem) {
.mm-09__bar {
flex-direction: column;
align-items: stretch;
padding-block: 0.6rem;
}
.mm-09__list {
flex-direction: column;
}
.mm-09__utils {
margin-inline-start: 0;
}
.mm-09__panel {
position: static;
opacity: 1;
visibility: visible;
pointer-events: auto;
display: none;
}
.mm-09__item--open > .mm-09__panel,
.mm-09__item:focus-within > .mm-09__panel {
display: block;
}
.mm-09__panel-inner {
inline-size: 100%;
}
}
@media (prefers-reduced-motion: reduce) {
.mm-09__panel {
transition-duration: 1ms;
}
}
@media (hover: hover) and (pointer: fine) {
.mm-09__trigger {
position: relative;
}
.mm-09__item:hover > .mm-09__trigger::after,
.mm-09__item:focus-within > .mm-09__trigger::after {
content: "";
position: absolute;
inset-inline: 0;
inset-block-start: 100%;
block-size: 16px;
}
}
/* Entry signature — rows switch on staccato with no fade, then the feature block glides up */
.mm-09__links li {
opacity: 0;
transition: opacity 1ms steps(1, end);
}
.mm-09__item:hover > .mm-09__panel .mm-09__links li,
.mm-09__item:focus-within > .mm-09__panel .mm-09__links li,
.mm-09__item--open > .mm-09__panel .mm-09__links li {
opacity: 1;
}
.mm-09__links li:nth-child(1) {
transition-delay: 30ms;
}
.mm-09__links li:nth-child(2) {
transition-delay: 80ms;
}
.mm-09__links li:nth-child(3) {
transition-delay: 130ms;
}
.mm-09__links li:nth-child(4) {
transition-delay: 180ms;
}
.mm-09__links li:nth-child(5) {
transition-delay: 230ms;
}
.mm-09__links li:nth-child(6) {
transition-delay: 280ms;
}
.mm-09__links li:nth-child(n+7) {
transition-delay: 280ms;
}
.mm-09__feature {
opacity: 0;
translate: 0 10px;
transition: opacity 260ms ease 240ms, translate 340ms cubic-bezier(0.22, 1, 0.36, 1) 240ms;
}
.mm-09__item:hover > .mm-09__panel .mm-09__feature,
.mm-09__item:focus-within > .mm-09__panel .mm-09__feature,
.mm-09__item--open > .mm-09__panel .mm-09__feature {
opacity: 1;
translate: 0 0;
}
@media (prefers-reduced-motion: reduce) {
.mm-09__links li,
.mm-09__feature {
transition-duration: 1ms;
transition-delay: 0s;
animation: none;
}
.mm-09__links li {
opacity: 1;
}
.mm-09__feature {
opacity: 1;
translate: none;
}
}Here's a working CSS Mega Menu from CodeFronts. Use it as-is or adapt to your framework. All classes are scoped under a unique prefix so the code won't collide with your existing styles. MIT licensed.
Demo: ARIA for Disclosure Style Navigation Panels
Source: https://codefronts.com/navigation/css-mega-menus/aria-for-disclosure-style-navigation-panels/
The boundary marker for the whole collection, shipped as a working retail header. role="menu" and role="menuitem" belong to application menus and bring keyboard conventions that are wrong for navigation links. This panel is a disclosure instead: a <button> with aria-expanded and aria-controls, a named region, real lists, real links and aria-current="page" on the active one.
## HTML
```html
<section class="mm-09" aria-labelledby="mm-09-title">
<h2 class="mm-09__sr" id="mm-09-title">Aperture</h2>
<div class="mm-09__theme">
<input class="mm-09__theme-input" type="checkbox" id="mm-09-theme">
<label class="mm-09__theme-label" for="mm-09-theme">
<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false"><circle cx="12" cy="12" r="8.5" fill="none" stroke="currentColor" stroke-width="1.6"/><path d="M12 3.5a8.5 8.5 0 0 0 0 17Z" fill="currentColor"/></svg>
<span class="mm-09__sr">Toggle dark theme</span>
</label>
</div>
<header class="mm-09__header">
<div class="mm-09__bar">
<a class="mm-09__brand" href="#mm-09-title">
<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false"><circle cx="12" cy="12" r="8.5" fill="none" stroke="currentColor" stroke-width="1.7"/><path d="M12 3.5 16 11h-8Zm8.2 5.6L16 16l4.2 1.1ZM3.8 9.1 8 16l-4.2 1.1Z" fill="currentColor"/></svg>
APERTURE
</a>
<nav class="mm-09__nav" aria-label="Primary">
<ul class="mm-09__list">
<li class="mm-09__item">
<button class="mm-09__trigger" type="button" id="mm-09-trigger-products" aria-expanded="false" aria-controls="mm-09-panel-products">Products</button>
<div class="mm-09__panel" id="mm-09-panel-products" aria-labelledby="mm-09-trigger-products">
<div class="mm-09__panel-inner">
<section class="mm-09__col" aria-labelledby="mm-09-h-bodies">
<h3 class="mm-09__col-head" id="mm-09-h-bodies">Bodies</h3>
<ul class="mm-09__links">
<li><a href="#mm-09-title">Full frame</a></li>
<li><a href="#mm-09-title">APS-C</a></li>
<li><a href="#mm-09-title">Medium format</a></li>
<li><a href="#mm-09-title">Rangefinder</a></li>
</ul>
</section>
<section class="mm-09__col" aria-labelledby="mm-09-h-glass">
<h3 class="mm-09__col-head" id="mm-09-h-glass">Lenses</h3>
<ul class="mm-09__links">
<li><a href="#mm-09-title" aria-current="page">Primes</a></li>
<li><a href="#mm-09-title">Zooms</a></li>
<li><a href="#mm-09-title">Tilt-shift</a></li>
<li><a href="#mm-09-title">Adapters</a></li>
</ul>
</section>
<section class="mm-09__col" aria-labelledby="mm-09-h-light">
<h3 class="mm-09__col-head" id="mm-09-h-light">Lighting</h3>
<ul class="mm-09__links">
<li><a href="#mm-09-title">Strobes</a></li>
<li><a href="#mm-09-title">Continuous</a></li>
<li><a href="#mm-09-title">Modifiers</a></li>
</ul>
</section>
<dl class="mm-09__spec">
<div><dt>In stock today</dt><dd>412 items</dd></div>
<div><dt>Trade-in</dt><dd>Valuation in 24h</dd></div>
<div><dt>Rental</dt><dd>Next-day to 42 cities</dd></div>
</dl>
</div>
</div>
</li>
<li class="mm-09__item">
<button class="mm-09__trigger" type="button" id="mm-09-trigger-service" aria-expanded="false" aria-controls="mm-09-panel-service">Service</button>
<div class="mm-09__panel" id="mm-09-panel-service" aria-labelledby="mm-09-trigger-service">
<div class="mm-09__panel-inner">
<section class="mm-09__col" aria-labelledby="mm-09-h-repair">
<h3 class="mm-09__col-head" id="mm-09-h-repair">Repair</h3>
<ul class="mm-09__links"><li><a href="#mm-09-title">Sensor clean</a></li><li><a href="#mm-09-title">Shutter replacement</a></li><li><a href="#mm-09-title">Lens calibration</a></li></ul>
</section>
<section class="mm-09__col" aria-labelledby="mm-09-h-trade">
<h3 class="mm-09__col-head" id="mm-09-h-trade">Trade</h3>
<ul class="mm-09__links"><li><a href="#mm-09-title">Sell your kit</a></li><li><a href="#mm-09-title">Part exchange</a></li></ul>
</section>
<section class="mm-09__col" aria-labelledby="mm-09-h-learn9">
<h3 class="mm-09__col-head" id="mm-09-h-learn9">Learn</h3>
<ul class="mm-09__links"><li><a href="#mm-09-title">Workshops</a></li><li><a href="#mm-09-title">Darkroom hire</a></li></ul>
</section>
<dl class="mm-09__spec">
<div><dt>Turnaround</dt><dd>5 working days</dd></div>
<div><dt>Warranty</dt><dd>12 months on repairs</dd></div>
</dl>
</div>
</div>
</li>
<li class="mm-09__item"><a class="mm-09__plain" href="#mm-09-title">Used</a></li>
<li class="mm-09__item"><a class="mm-09__plain mm-09__plain--flag" href="#mm-09-title">Clearance</a></li>
</ul>
</nav>
<div class="mm-09__utils">
<a class="mm-09__util" href="#mm-09-title">Stores</a>
<a class="mm-09__util" href="#mm-09-title">Account</a>
<a class="mm-09__bag" href="#mm-09-title">Bag (1)</a>
</div>
</div>
</header>
<main class="mm-09__page">
<div class="mm-09__feature">
<p class="mm-09__feature-k">Primes / 35mm</p>
<h1 class="mm-09__feature-h">Aperture 35mm f/1.4 Mark III</h1>
<p class="mm-09__feature-p">Eleven elements, weather sealed, 420g. Built for the frame you did not plan for.</p>
<p class="mm-09__price">£1,290 <span>or £107/mo</span></p>
</div>
</main>
</section>
```
## CSS
```css
.mm-09 {
--mm-09-bg: #ffffff;
--mm-09-surf: #ffffff;
--mm-09-line: #111111;
--mm-09-soft: #ededed;
--mm-09-ink: #111111;
--mm-09-mut: #6b6b6b;
--mm-09-red: #d90429;
--mm-09-red: oklch(55% 0.23 25);
--mm-09-rule: 1px;
--mm-09-font-display: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
width: 100%;
min-height: 100vh;
min-height: 100svh;
display: block;
position: relative;
box-sizing: border-box;
background: var(--mm-09-bg);
color: var(--mm-09-ink);
font-family: system-ui, -apple-system, "Segoe UI", sans-serif;
line-height: 1.55;
}
.mm-09 *,
.mm-09 *::before,
.mm-09 *::after {
box-sizing: border-box;
}
.mm-09 :focus-visible {
outline: 2px solid var(--mm-09-red);
outline-offset: 2px;
}
.mm-09__sr {
position: absolute;
width: 1px;
height: 1px;
margin: -1px;
padding: 0;
overflow: hidden;
clip-path: inset(50%);
white-space: nowrap;
border: 0;
}
.mm-09:has(.mm-09__theme-input:checked) {
--mm-09-bg: #0b0b0b;
--mm-09-surf: #131313;
--mm-09-line: #f2f2f2;
--mm-09-soft: #262626;
--mm-09-ink: #f2f2f2;
--mm-09-mut: #a0a0a0;
--mm-09-red: #ff4d6d;
--mm-09-red: oklch(71% 0.18 20);
}
@media (prefers-color-scheme: dark) {
.mm-09 {
--mm-09-bg: #0b0b0b;
--mm-09-surf: #131313;
--mm-09-line: #f2f2f2;
--mm-09-soft: #262626;
--mm-09-ink: #f2f2f2;
--mm-09-mut: #a0a0a0;
--mm-09-red: #ff4d6d;
--mm-09-red: oklch(71% 0.18 20);
}
.mm-09:has(.mm-09__theme-input:checked) {
--mm-09-bg: #ffffff;
--mm-09-surf: #ffffff;
--mm-09-line: #111111;
--mm-09-soft: #ededed;
--mm-09-ink: #111111;
--mm-09-mut: #6b6b6b;
--mm-09-red: #d90429;
--mm-09-red: oklch(55% 0.23 25);
}
}
@media (prefers-color-scheme: light) {
.mm-09:has(.mm-09__theme-input:checked) {
--mm-09-bg: #0b0b0b;
--mm-09-surf: #131313;
--mm-09-line: #f2f2f2;
--mm-09-soft: #262626;
--mm-09-ink: #f2f2f2;
--mm-09-mut: #a0a0a0;
--mm-09-red: #ff4d6d;
--mm-09-red: oklch(71% 0.18 20);
}
}
.mm-09__theme {
position: absolute;
inset-block-start: 12px;
inset-inline-end: clamp(0.75rem, 3vw, 1.5rem);
z-index: 60;
}
.mm-09__theme-input {
position: absolute;
opacity: 0;
inline-size: 100%;
block-size: 100%;
margin: 0;
cursor: pointer;
}
.mm-09__theme-label {
display: grid;
place-items: center;
inline-size: 44px;
block-size: 44px;
border: var(--mm-09-rule) solid var(--mm-09-line);
background: var(--mm-09-surf);
color: var(--mm-09-ink);
cursor: pointer;
}
.mm-09__theme-label svg {
inline-size: 20px;
block-size: 20px;
}
.mm-09__theme-input:focus-visible + .mm-09__theme-label {
outline: 2px solid var(--mm-09-red);
outline-offset: 3px;
}
.mm-09__header {
position: relative;
z-index: 10;
inline-size: 100%;
border-block-end: 2px solid var(--mm-09-line);
background: var(--mm-09-surf);
}
.mm-09__bar {
inline-size: min(80rem, calc(100% - 2rem));
margin-inline: auto;
display: flex;
align-items: center;
gap: clamp(0.75rem, 3vw, 2.5rem);
flex-wrap: wrap;
min-block-size: 66px;
padding-inline-end: 60px;
}
.mm-09__brand {
display: inline-flex;
align-items: center;
gap: 0.5rem;
color: var(--mm-09-ink);
text-decoration: none;
font: 700 0.95rem/1 var(--mm-09-font-display);
letter-spacing: 0.22em;
}
.mm-09__brand svg {
inline-size: 22px;
block-size: 22px;
}
.mm-09__nav {
min-inline-size: 0;
}
.mm-09__list {
display: flex;
flex-wrap: wrap;
gap: clamp(0.15rem, 1.5vw, 0.5rem);
list-style: none;
margin: 0;
padding: 0;
min-inline-size: 0;
}
.mm-09__item {
position: static;
}
.mm-09__trigger,
.mm-09__plain {
display: inline-flex;
align-items: center;
min-block-size: 44px;
padding-inline: 0.6rem;
border: 0;
background: transparent;
color: var(--mm-09-ink);
font: 600 0.82rem/1 var(--mm-09-font-display);
letter-spacing: 0.14em;
text-transform: uppercase;
text-decoration: none;
cursor: pointer;
}
.mm-09__item--open > .mm-09__trigger,
.mm-09__item:hover > .mm-09__trigger,
.mm-09__item:focus-within > .mm-09__trigger {
background: var(--mm-09-ink);
color: var(--mm-09-bg);
}
.mm-09__plain--flag {
color: var(--mm-09-red);
}
.mm-09__utils {
margin-inline-start: auto;
display: flex;
align-items: center;
gap: 0.9rem;
}
.mm-09__util {
color: var(--mm-09-mut);
text-decoration: none;
font: 500 0.78rem/1 var(--mm-09-font-display);
letter-spacing: 0.1em;
text-transform: uppercase;
display: inline-flex;
align-items: center;
min-block-size: 44px;
}
.mm-09__bag {
display: inline-flex;
align-items: center;
min-block-size: 34px;
padding-inline: 0.7rem;
border: var(--mm-09-rule) solid var(--mm-09-line);
color: var(--mm-09-ink);
text-decoration: none;
font: 600 0.75rem/1 var(--mm-09-font-display);
letter-spacing: 0.1em;
text-transform: uppercase;
}
.mm-09__panel {
position: absolute;
inset-inline: 0;
inset-block-start: 100%;
z-index: 30;
background: var(--mm-09-surf);
border-block-end: 2px solid var(--mm-09-line);
opacity: 0;
visibility: hidden;
pointer-events: none;
transition: opacity 150ms ease, visibility 0s linear 150ms;
}
.mm-09__item--open > .mm-09__panel,
.mm-09__item:focus-within > .mm-09__panel {
opacity: 1;
visibility: visible;
pointer-events: auto;
transition-delay: 0s;
}
@media (hover: hover) {
.mm-09__item:hover > .mm-09__panel {
opacity: 1;
visibility: visible;
pointer-events: auto;
transition-delay: 0s;
}
}
.mm-09__panel-inner {
inline-size: min(80rem, calc(100% - 2rem));
margin-inline: auto;
display: grid;
grid-template-columns: repeat(auto-fit, minmax(min(100%, 11rem), 1fr));
gap: 0 clamp(1rem, 4vw, 3rem);
padding-block: clamp(1.1rem, 3vw, 1.9rem);
}
.mm-09__col {
min-inline-size: 0;
}
.mm-09__col-head {
margin: 0 0 0.4rem;
padding-block-end: 0.35rem;
border-block-end: 2px solid var(--mm-09-line);
font: 700 0.7rem/1 var(--mm-09-font-display);
letter-spacing: 0.18em;
text-transform: uppercase;
}
.mm-09__links {
list-style: none;
margin: 0;
padding: 0;
display: grid;
}
.mm-09__links a {
display: flex;
align-items: center;
min-block-size: 44px;
color: var(--mm-09-ink);
text-decoration: none;
font-size: 0.9rem;
border-block-end: var(--mm-09-rule) solid var(--mm-09-soft);
min-inline-size: 0;
}
.mm-09__links a:hover {
color: var(--mm-09-red);
}
.mm-09__links a[aria-current="page"] {
font-weight: 700;
box-shadow: inset 3px 0 0 var(--mm-09-red);
padding-inline-start: 0.5rem;
}
.mm-09__spec {
display: grid;
align-content: start;
gap: 0.6rem;
margin: 0;
padding: 0.9rem 1rem;
background: var(--mm-09-soft);
min-inline-size: 0;
}
.mm-09__spec dt {
font: 700 0.62rem/1 var(--mm-09-font-display);
letter-spacing: 0.16em;
text-transform: uppercase;
color: var(--mm-09-mut);
}
.mm-09__spec dd {
margin: 0.15rem 0 0;
font-size: 0.86rem;
}
.mm-09__page {
inline-size: min(80rem, calc(100% - 2rem));
margin-inline: auto;
padding-block: clamp(2.5rem, 8vw, 5rem);
}
.mm-09__feature {
max-inline-size: 40rem;
display: grid;
gap: 0.5rem;
}
.mm-09__feature-k {
margin: 0;
font: 600 0.72rem/1 var(--mm-09-font-display);
letter-spacing: 0.2em;
text-transform: uppercase;
color: var(--mm-09-red);
}
.mm-09__feature-h {
margin: 0;
font: 400 clamp(1.9rem, 6vw, 3.2rem)/1.05 var(--mm-09-font-display);
letter-spacing: -0.04em;
text-wrap: balance;
}
.mm-09__feature-p {
margin: 0;
color: var(--mm-09-mut);
font-size: clamp(0.95rem, 2.3vw, 1.05rem);
text-wrap: pretty;
}
.mm-09__price {
margin: 0.4rem 0 0;
font: 700 1.6rem/1 var(--mm-09-font-display);
font-variant-numeric: tabular-nums;
}
.mm-09__price span {
font: 400 0.85rem/1 var(--mm-09-font-display);
color: var(--mm-09-mut);
}
@media (max-width: 52rem) {
.mm-09__bar {
flex-direction: column;
align-items: stretch;
padding-block: 0.6rem;
}
.mm-09__list {
flex-direction: column;
}
.mm-09__utils {
margin-inline-start: 0;
}
.mm-09__panel {
position: static;
opacity: 1;
visibility: visible;
pointer-events: auto;
display: none;
}
.mm-09__item--open > .mm-09__panel,
.mm-09__item:focus-within > .mm-09__panel {
display: block;
}
.mm-09__panel-inner {
inline-size: 100%;
}
}
@media (prefers-reduced-motion: reduce) {
.mm-09__panel {
transition-duration: 1ms;
}
}
@media (hover: hover) and (pointer: fine) {
.mm-09__trigger {
position: relative;
}
.mm-09__item:hover > .mm-09__trigger::after,
.mm-09__item:focus-within > .mm-09__trigger::after {
content: "";
position: absolute;
inset-inline: 0;
inset-block-start: 100%;
block-size: 16px;
}
}
/* Entry signature — rows switch on staccato with no fade, then the feature block glides up */
.mm-09__links li {
opacity: 0;
transition: opacity 1ms steps(1, end);
}
.mm-09__item:hover > .mm-09__panel .mm-09__links li,
.mm-09__item:focus-within > .mm-09__panel .mm-09__links li,
.mm-09__item--open > .mm-09__panel .mm-09__links li {
opacity: 1;
}
.mm-09__links li:nth-child(1) {
transition-delay: 30ms;
}
.mm-09__links li:nth-child(2) {
transition-delay: 80ms;
}
.mm-09__links li:nth-child(3) {
transition-delay: 130ms;
}
.mm-09__links li:nth-child(4) {
transition-delay: 180ms;
}
.mm-09__links li:nth-child(5) {
transition-delay: 230ms;
}
.mm-09__links li:nth-child(6) {
transition-delay: 280ms;
}
.mm-09__links li:nth-child(n+7) {
transition-delay: 280ms;
}
.mm-09__feature {
opacity: 0;
translate: 0 10px;
transition: opacity 260ms ease 240ms, translate 340ms cubic-bezier(0.22, 1, 0.36, 1) 240ms;
}
.mm-09__item:hover > .mm-09__panel .mm-09__feature,
.mm-09__item:focus-within > .mm-09__panel .mm-09__feature,
.mm-09__item--open > .mm-09__panel .mm-09__feature {
opacity: 1;
translate: 0 0;
}
@media (prefers-reduced-motion: reduce) {
.mm-09__links li,
.mm-09__feature {
transition-duration: 1ms;
transition-delay: 0s;
animation: none;
}
.mm-09__links li {
opacity: 1;
}
.mm-09__feature {
opacity: 1;
translate: none;
}
}
```Here's a working CSS Mega Menu from CodeFronts. Use it as-is or adapt to your framework. All classes are scoped under a unique prefix so the code won't collide with your existing styles. MIT licensed.
Demo: ARIA for Disclosure Style Navigation Panels
Source: https://codefronts.com/navigation/css-mega-menus/aria-for-disclosure-style-navigation-panels/
The boundary marker for the whole collection, shipped as a working retail header. role="menu" and role="menuitem" belong to application menus and bring keyboard conventions that are wrong for navigation links. This panel is a disclosure instead: a <button> with aria-expanded and aria-controls, a named region, real lists, real links and aria-current="page" on the active one.
## HTML
```html
<section class="mm-09" aria-labelledby="mm-09-title">
<h2 class="mm-09__sr" id="mm-09-title">Aperture</h2>
<div class="mm-09__theme">
<input class="mm-09__theme-input" type="checkbox" id="mm-09-theme">
<label class="mm-09__theme-label" for="mm-09-theme">
<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false"><circle cx="12" cy="12" r="8.5" fill="none" stroke="currentColor" stroke-width="1.6"/><path d="M12 3.5a8.5 8.5 0 0 0 0 17Z" fill="currentColor"/></svg>
<span class="mm-09__sr">Toggle dark theme</span>
</label>
</div>
<header class="mm-09__header">
<div class="mm-09__bar">
<a class="mm-09__brand" href="#mm-09-title">
<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false"><circle cx="12" cy="12" r="8.5" fill="none" stroke="currentColor" stroke-width="1.7"/><path d="M12 3.5 16 11h-8Zm8.2 5.6L16 16l4.2 1.1ZM3.8 9.1 8 16l-4.2 1.1Z" fill="currentColor"/></svg>
APERTURE
</a>
<nav class="mm-09__nav" aria-label="Primary">
<ul class="mm-09__list">
<li class="mm-09__item">
<button class="mm-09__trigger" type="button" id="mm-09-trigger-products" aria-expanded="false" aria-controls="mm-09-panel-products">Products</button>
<div class="mm-09__panel" id="mm-09-panel-products" aria-labelledby="mm-09-trigger-products">
<div class="mm-09__panel-inner">
<section class="mm-09__col" aria-labelledby="mm-09-h-bodies">
<h3 class="mm-09__col-head" id="mm-09-h-bodies">Bodies</h3>
<ul class="mm-09__links">
<li><a href="#mm-09-title">Full frame</a></li>
<li><a href="#mm-09-title">APS-C</a></li>
<li><a href="#mm-09-title">Medium format</a></li>
<li><a href="#mm-09-title">Rangefinder</a></li>
</ul>
</section>
<section class="mm-09__col" aria-labelledby="mm-09-h-glass">
<h3 class="mm-09__col-head" id="mm-09-h-glass">Lenses</h3>
<ul class="mm-09__links">
<li><a href="#mm-09-title" aria-current="page">Primes</a></li>
<li><a href="#mm-09-title">Zooms</a></li>
<li><a href="#mm-09-title">Tilt-shift</a></li>
<li><a href="#mm-09-title">Adapters</a></li>
</ul>
</section>
<section class="mm-09__col" aria-labelledby="mm-09-h-light">
<h3 class="mm-09__col-head" id="mm-09-h-light">Lighting</h3>
<ul class="mm-09__links">
<li><a href="#mm-09-title">Strobes</a></li>
<li><a href="#mm-09-title">Continuous</a></li>
<li><a href="#mm-09-title">Modifiers</a></li>
</ul>
</section>
<dl class="mm-09__spec">
<div><dt>In stock today</dt><dd>412 items</dd></div>
<div><dt>Trade-in</dt><dd>Valuation in 24h</dd></div>
<div><dt>Rental</dt><dd>Next-day to 42 cities</dd></div>
</dl>
</div>
</div>
</li>
<li class="mm-09__item">
<button class="mm-09__trigger" type="button" id="mm-09-trigger-service" aria-expanded="false" aria-controls="mm-09-panel-service">Service</button>
<div class="mm-09__panel" id="mm-09-panel-service" aria-labelledby="mm-09-trigger-service">
<div class="mm-09__panel-inner">
<section class="mm-09__col" aria-labelledby="mm-09-h-repair">
<h3 class="mm-09__col-head" id="mm-09-h-repair">Repair</h3>
<ul class="mm-09__links"><li><a href="#mm-09-title">Sensor clean</a></li><li><a href="#mm-09-title">Shutter replacement</a></li><li><a href="#mm-09-title">Lens calibration</a></li></ul>
</section>
<section class="mm-09__col" aria-labelledby="mm-09-h-trade">
<h3 class="mm-09__col-head" id="mm-09-h-trade">Trade</h3>
<ul class="mm-09__links"><li><a href="#mm-09-title">Sell your kit</a></li><li><a href="#mm-09-title">Part exchange</a></li></ul>
</section>
<section class="mm-09__col" aria-labelledby="mm-09-h-learn9">
<h3 class="mm-09__col-head" id="mm-09-h-learn9">Learn</h3>
<ul class="mm-09__links"><li><a href="#mm-09-title">Workshops</a></li><li><a href="#mm-09-title">Darkroom hire</a></li></ul>
</section>
<dl class="mm-09__spec">
<div><dt>Turnaround</dt><dd>5 working days</dd></div>
<div><dt>Warranty</dt><dd>12 months on repairs</dd></div>
</dl>
</div>
</div>
</li>
<li class="mm-09__item"><a class="mm-09__plain" href="#mm-09-title">Used</a></li>
<li class="mm-09__item"><a class="mm-09__plain mm-09__plain--flag" href="#mm-09-title">Clearance</a></li>
</ul>
</nav>
<div class="mm-09__utils">
<a class="mm-09__util" href="#mm-09-title">Stores</a>
<a class="mm-09__util" href="#mm-09-title">Account</a>
<a class="mm-09__bag" href="#mm-09-title">Bag (1)</a>
</div>
</div>
</header>
<main class="mm-09__page">
<div class="mm-09__feature">
<p class="mm-09__feature-k">Primes / 35mm</p>
<h1 class="mm-09__feature-h">Aperture 35mm f/1.4 Mark III</h1>
<p class="mm-09__feature-p">Eleven elements, weather sealed, 420g. Built for the frame you did not plan for.</p>
<p class="mm-09__price">£1,290 <span>or £107/mo</span></p>
</div>
</main>
</section>
```
## CSS
```css
.mm-09 {
--mm-09-bg: #ffffff;
--mm-09-surf: #ffffff;
--mm-09-line: #111111;
--mm-09-soft: #ededed;
--mm-09-ink: #111111;
--mm-09-mut: #6b6b6b;
--mm-09-red: #d90429;
--mm-09-red: oklch(55% 0.23 25);
--mm-09-rule: 1px;
--mm-09-font-display: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
width: 100%;
min-height: 100vh;
min-height: 100svh;
display: block;
position: relative;
box-sizing: border-box;
background: var(--mm-09-bg);
color: var(--mm-09-ink);
font-family: system-ui, -apple-system, "Segoe UI", sans-serif;
line-height: 1.55;
}
.mm-09 *,
.mm-09 *::before,
.mm-09 *::after {
box-sizing: border-box;
}
.mm-09 :focus-visible {
outline: 2px solid var(--mm-09-red);
outline-offset: 2px;
}
.mm-09__sr {
position: absolute;
width: 1px;
height: 1px;
margin: -1px;
padding: 0;
overflow: hidden;
clip-path: inset(50%);
white-space: nowrap;
border: 0;
}
.mm-09:has(.mm-09__theme-input:checked) {
--mm-09-bg: #0b0b0b;
--mm-09-surf: #131313;
--mm-09-line: #f2f2f2;
--mm-09-soft: #262626;
--mm-09-ink: #f2f2f2;
--mm-09-mut: #a0a0a0;
--mm-09-red: #ff4d6d;
--mm-09-red: oklch(71% 0.18 20);
}
@media (prefers-color-scheme: dark) {
.mm-09 {
--mm-09-bg: #0b0b0b;
--mm-09-surf: #131313;
--mm-09-line: #f2f2f2;
--mm-09-soft: #262626;
--mm-09-ink: #f2f2f2;
--mm-09-mut: #a0a0a0;
--mm-09-red: #ff4d6d;
--mm-09-red: oklch(71% 0.18 20);
}
.mm-09:has(.mm-09__theme-input:checked) {
--mm-09-bg: #ffffff;
--mm-09-surf: #ffffff;
--mm-09-line: #111111;
--mm-09-soft: #ededed;
--mm-09-ink: #111111;
--mm-09-mut: #6b6b6b;
--mm-09-red: #d90429;
--mm-09-red: oklch(55% 0.23 25);
}
}
@media (prefers-color-scheme: light) {
.mm-09:has(.mm-09__theme-input:checked) {
--mm-09-bg: #0b0b0b;
--mm-09-surf: #131313;
--mm-09-line: #f2f2f2;
--mm-09-soft: #262626;
--mm-09-ink: #f2f2f2;
--mm-09-mut: #a0a0a0;
--mm-09-red: #ff4d6d;
--mm-09-red: oklch(71% 0.18 20);
}
}
.mm-09__theme {
position: absolute;
inset-block-start: 12px;
inset-inline-end: clamp(0.75rem, 3vw, 1.5rem);
z-index: 60;
}
.mm-09__theme-input {
position: absolute;
opacity: 0;
inline-size: 100%;
block-size: 100%;
margin: 0;
cursor: pointer;
}
.mm-09__theme-label {
display: grid;
place-items: center;
inline-size: 44px;
block-size: 44px;
border: var(--mm-09-rule) solid var(--mm-09-line);
background: var(--mm-09-surf);
color: var(--mm-09-ink);
cursor: pointer;
}
.mm-09__theme-label svg {
inline-size: 20px;
block-size: 20px;
}
.mm-09__theme-input:focus-visible + .mm-09__theme-label {
outline: 2px solid var(--mm-09-red);
outline-offset: 3px;
}
.mm-09__header {
position: relative;
z-index: 10;
inline-size: 100%;
border-block-end: 2px solid var(--mm-09-line);
background: var(--mm-09-surf);
}
.mm-09__bar {
inline-size: min(80rem, calc(100% - 2rem));
margin-inline: auto;
display: flex;
align-items: center;
gap: clamp(0.75rem, 3vw, 2.5rem);
flex-wrap: wrap;
min-block-size: 66px;
padding-inline-end: 60px;
}
.mm-09__brand {
display: inline-flex;
align-items: center;
gap: 0.5rem;
color: var(--mm-09-ink);
text-decoration: none;
font: 700 0.95rem/1 var(--mm-09-font-display);
letter-spacing: 0.22em;
}
.mm-09__brand svg {
inline-size: 22px;
block-size: 22px;
}
.mm-09__nav {
min-inline-size: 0;
}
.mm-09__list {
display: flex;
flex-wrap: wrap;
gap: clamp(0.15rem, 1.5vw, 0.5rem);
list-style: none;
margin: 0;
padding: 0;
min-inline-size: 0;
}
.mm-09__item {
position: static;
}
.mm-09__trigger,
.mm-09__plain {
display: inline-flex;
align-items: center;
min-block-size: 44px;
padding-inline: 0.6rem;
border: 0;
background: transparent;
color: var(--mm-09-ink);
font: 600 0.82rem/1 var(--mm-09-font-display);
letter-spacing: 0.14em;
text-transform: uppercase;
text-decoration: none;
cursor: pointer;
}
.mm-09__item--open > .mm-09__trigger,
.mm-09__item:hover > .mm-09__trigger,
.mm-09__item:focus-within > .mm-09__trigger {
background: var(--mm-09-ink);
color: var(--mm-09-bg);
}
.mm-09__plain--flag {
color: var(--mm-09-red);
}
.mm-09__utils {
margin-inline-start: auto;
display: flex;
align-items: center;
gap: 0.9rem;
}
.mm-09__util {
color: var(--mm-09-mut);
text-decoration: none;
font: 500 0.78rem/1 var(--mm-09-font-display);
letter-spacing: 0.1em;
text-transform: uppercase;
display: inline-flex;
align-items: center;
min-block-size: 44px;
}
.mm-09__bag {
display: inline-flex;
align-items: center;
min-block-size: 34px;
padding-inline: 0.7rem;
border: var(--mm-09-rule) solid var(--mm-09-line);
color: var(--mm-09-ink);
text-decoration: none;
font: 600 0.75rem/1 var(--mm-09-font-display);
letter-spacing: 0.1em;
text-transform: uppercase;
}
.mm-09__panel {
position: absolute;
inset-inline: 0;
inset-block-start: 100%;
z-index: 30;
background: var(--mm-09-surf);
border-block-end: 2px solid var(--mm-09-line);
opacity: 0;
visibility: hidden;
pointer-events: none;
transition: opacity 150ms ease, visibility 0s linear 150ms;
}
.mm-09__item--open > .mm-09__panel,
.mm-09__item:focus-within > .mm-09__panel {
opacity: 1;
visibility: visible;
pointer-events: auto;
transition-delay: 0s;
}
@media (hover: hover) {
.mm-09__item:hover > .mm-09__panel {
opacity: 1;
visibility: visible;
pointer-events: auto;
transition-delay: 0s;
}
}
.mm-09__panel-inner {
inline-size: min(80rem, calc(100% - 2rem));
margin-inline: auto;
display: grid;
grid-template-columns: repeat(auto-fit, minmax(min(100%, 11rem), 1fr));
gap: 0 clamp(1rem, 4vw, 3rem);
padding-block: clamp(1.1rem, 3vw, 1.9rem);
}
.mm-09__col {
min-inline-size: 0;
}
.mm-09__col-head {
margin: 0 0 0.4rem;
padding-block-end: 0.35rem;
border-block-end: 2px solid var(--mm-09-line);
font: 700 0.7rem/1 var(--mm-09-font-display);
letter-spacing: 0.18em;
text-transform: uppercase;
}
.mm-09__links {
list-style: none;
margin: 0;
padding: 0;
display: grid;
}
.mm-09__links a {
display: flex;
align-items: center;
min-block-size: 44px;
color: var(--mm-09-ink);
text-decoration: none;
font-size: 0.9rem;
border-block-end: var(--mm-09-rule) solid var(--mm-09-soft);
min-inline-size: 0;
}
.mm-09__links a:hover {
color: var(--mm-09-red);
}
.mm-09__links a[aria-current="page"] {
font-weight: 700;
box-shadow: inset 3px 0 0 var(--mm-09-red);
padding-inline-start: 0.5rem;
}
.mm-09__spec {
display: grid;
align-content: start;
gap: 0.6rem;
margin: 0;
padding: 0.9rem 1rem;
background: var(--mm-09-soft);
min-inline-size: 0;
}
.mm-09__spec dt {
font: 700 0.62rem/1 var(--mm-09-font-display);
letter-spacing: 0.16em;
text-transform: uppercase;
color: var(--mm-09-mut);
}
.mm-09__spec dd {
margin: 0.15rem 0 0;
font-size: 0.86rem;
}
.mm-09__page {
inline-size: min(80rem, calc(100% - 2rem));
margin-inline: auto;
padding-block: clamp(2.5rem, 8vw, 5rem);
}
.mm-09__feature {
max-inline-size: 40rem;
display: grid;
gap: 0.5rem;
}
.mm-09__feature-k {
margin: 0;
font: 600 0.72rem/1 var(--mm-09-font-display);
letter-spacing: 0.2em;
text-transform: uppercase;
color: var(--mm-09-red);
}
.mm-09__feature-h {
margin: 0;
font: 400 clamp(1.9rem, 6vw, 3.2rem)/1.05 var(--mm-09-font-display);
letter-spacing: -0.04em;
text-wrap: balance;
}
.mm-09__feature-p {
margin: 0;
color: var(--mm-09-mut);
font-size: clamp(0.95rem, 2.3vw, 1.05rem);
text-wrap: pretty;
}
.mm-09__price {
margin: 0.4rem 0 0;
font: 700 1.6rem/1 var(--mm-09-font-display);
font-variant-numeric: tabular-nums;
}
.mm-09__price span {
font: 400 0.85rem/1 var(--mm-09-font-display);
color: var(--mm-09-mut);
}
@media (max-width: 52rem) {
.mm-09__bar {
flex-direction: column;
align-items: stretch;
padding-block: 0.6rem;
}
.mm-09__list {
flex-direction: column;
}
.mm-09__utils {
margin-inline-start: 0;
}
.mm-09__panel {
position: static;
opacity: 1;
visibility: visible;
pointer-events: auto;
display: none;
}
.mm-09__item--open > .mm-09__panel,
.mm-09__item:focus-within > .mm-09__panel {
display: block;
}
.mm-09__panel-inner {
inline-size: 100%;
}
}
@media (prefers-reduced-motion: reduce) {
.mm-09__panel {
transition-duration: 1ms;
}
}
@media (hover: hover) and (pointer: fine) {
.mm-09__trigger {
position: relative;
}
.mm-09__item:hover > .mm-09__trigger::after,
.mm-09__item:focus-within > .mm-09__trigger::after {
content: "";
position: absolute;
inset-inline: 0;
inset-block-start: 100%;
block-size: 16px;
}
}
/* Entry signature — rows switch on staccato with no fade, then the feature block glides up */
.mm-09__links li {
opacity: 0;
transition: opacity 1ms steps(1, end);
}
.mm-09__item:hover > .mm-09__panel .mm-09__links li,
.mm-09__item:focus-within > .mm-09__panel .mm-09__links li,
.mm-09__item--open > .mm-09__panel .mm-09__links li {
opacity: 1;
}
.mm-09__links li:nth-child(1) {
transition-delay: 30ms;
}
.mm-09__links li:nth-child(2) {
transition-delay: 80ms;
}
.mm-09__links li:nth-child(3) {
transition-delay: 130ms;
}
.mm-09__links li:nth-child(4) {
transition-delay: 180ms;
}
.mm-09__links li:nth-child(5) {
transition-delay: 230ms;
}
.mm-09__links li:nth-child(6) {
transition-delay: 280ms;
}
.mm-09__links li:nth-child(n+7) {
transition-delay: 280ms;
}
.mm-09__feature {
opacity: 0;
translate: 0 10px;
transition: opacity 260ms ease 240ms, translate 340ms cubic-bezier(0.22, 1, 0.36, 1) 240ms;
}
.mm-09__item:hover > .mm-09__panel .mm-09__feature,
.mm-09__item:focus-within > .mm-09__panel .mm-09__feature,
.mm-09__item--open > .mm-09__panel .mm-09__feature {
opacity: 1;
translate: 0 0;
}
@media (prefers-reduced-motion: reduce) {
.mm-09__links li,
.mm-09__feature {
transition-duration: 1ms;
transition-delay: 0s;
animation: none;
}
.mm-09__links li {
opacity: 1;
}
.mm-09__feature {
opacity: 1;
translate: none;
}
}
```How this works
A menu in ARIA is an application widget, not a navigation region. role="menu" comes from desktop software: File, Edit, View. It carries an interaction contract — arrow keys move between items, Tab exits the whole menu, typing a letter jumps to a matching item — and assistive technology switches into application mode to honour it. If you apply that role to a list of links, you have promised a widget you did not build.
The cost is concrete, not stylistic. Inside role="menu", children with role="menuitem" stop being announced as links. A screen reader user loses the link count, loses "visited", and often loses the ability to use link-navigation commands to move through the panel. They are told to expect a menu and given something that behaves like a page. The most common bug report from this is simply "the menu doesn't work", because Tab is doing something the role said it would not.
A disclosure is the honest description of a mega menu. A button that shows and hides some content. aria-expanded on the button describes the state, aria-controls associates it with the panel, and everything inside stays exactly what it is. Nothing needs a role because the native elements already have the right ones. That is the pattern this whole collection is built on.
The one case for role="menu": a genuine application menu — actions rather than destinations, arrow-key driven, keyboard conventions fully implemented. An editor's File menu qualifies. A shop's Cameras panel does not, even when it is large and even when it is behind a button. If the items navigate, they are links.
Make it yours
- Change
aria-current="page"toaria-current="true"if the highlighted item is a section rather than the exact page. - Swap the panel's
aria-labelledbyfor an explicitaria-labelif the trigger's text is not a good name for the region. - Retune
--mm-09-rulefor a heavier or lighter editorial grid. - Change
--mm-09-redto recolour the current-page marker and the sale flag together. - Drop the specification strip in the panel for a plain two-column link list.
- Recolour with the two
--mm-09-reddeclarations, hex first then oklch.
Gotchas — read before shipping
role="menu"on navigation is the single most common ARIA mistake in mega menus, and it makes the experience measurably worse rather than merely redundant.aria-controlspointing at an id that does not exist in the document is silently ignored. In a page with several demos, unnamespaced ids make this happen without any visible symptom.aria-haspopup="true"means specifically a menu popup and implies the menu keyboard model. For a disclosure panel, leave it off.- Two
<nav>elements without distinct labels are announced identically, so a user cannot tell primary navigation from a footer. - Adding
role="navigation"to a<nav>element is redundant. The element already has it; the label is the part that is missing.
Browser support
| Chrome | Safari | Firefox | Edge |
|---|---|---|---|
| 114+ | 17.5+ | 121+ | 114+ |
Floor set by :has(), oklch(), text-wrap as this demo is written. The core technique itself goes back further — Chrome 111+.
oklch() and the :has() theme toggle set the floor. aria-expanded, aria-controls and aria-current are long-standing ARIA attributes with universal support, so the accessibility layer contributes nothing; below the oklch() floor the sRGB hex declared first applies and every announcement is unchanged.