Events Css Menu February 24, 2026 5 min read 0 views Skip to content Home Products Product A Product B Services ▾ Service A Service B Help Docs FAQ Tutorials Community Forum Events … > **Key Points** > * `role="navigation"` + `aria-label` – makes the `` recognizable by assistive tech. > * `menu__item--has-submenu` – flag for items that contain a sub‑menu. > * For the click‑sub‑menu we use a hidden `` that is toggled by a ``. > * The sub‑menus are ``. --- 2. Base CSScss /* ── Global resets & helpers ─────────────────────────────────────── */ *, *::before, *::after { box-sizing: border-box; } html { font-size: 16px; } body { font-family: system-ui, sans-serif; line-height: 1.5; margin: 0; } a { text-decoration: none; color: inherit; } .skip-link { position: absolute; top: -40px; left: 0; background: #000; color: #fff; padding: .5rem 1rem; transition: top .3s; } .skip-link:focus { top: 0; } /* ── Navigation styles ─────────────────────────────────────────── */ .primary-nav .menu { list-style: none; margin: 0; padding: 0; display: flex; } .menu__item { position: relative; } .menu__link { display: block; padding: .75rem 1.25rem; } .menu__link:focus { outline: 2px solid #0066ff; outline-offset: 2px; } /* Sub‑menu – hidden by default */ .submenu { position: absolute; left: 0; top: 100%; background: #fff; min-width: 200px; padding: .5rem 0; box-shadow: 0 4px 6px rgba(0,0,0,.1); opacity: 0; visibility: hidden; transform: translateY(10px); transition: opacity .2s ease, transform .2s ease; z-index: 999; list-style: none; } .submenu .menu__link { padding: .5rem 1rem; white-space: nowrap; } /* For mega‑menus (Grid) */ .mega-menu { display: grid; grid-template-columns: repeat(2, 1fr); gap: 1rem; } /* Utility for screen readers */ .hidden-visually { position: absolute; width: 1px; height: 1px; clip: rect(0 0 0 0); overflow: hidden; } > This base sets up a responsive flex‑row menu. > All sub‑menus start hidden (`opacity: 0; visibility: hidden;`). > `transform: translateY(10px)` gives a small “slide‑down” feel. --- 3. Hover‑Activated Sub‑Menu Add this to the CSS file:css /* Hover: show submenu on mouseover */ .menu__item--has-submenu:hover > .submenu, .menu__item--has-submenu:focus-within > .submenu { opacity: 1; visibility: visible; transform: translateY(0); } /* Keep focus styles for keyboard users */ .menu__item--has-submenu:focus-within > .submenu .menu__link { outline: 2px solid #0066ff; /* or your focus color */ } Explanation | Selector | What it does | |----------|--------------| | `.menu__item--has-submenu:hover > .submenu` | Reveals the submenu when the mouse hovers over the parent ` | | .menu__item--has-submenu:focus-within > .submenu` | Keeps the submenu visible when any descendant receives focus (keyboard navigation). | Tip: For touch devices, :hover is not reliable; the click‑activated submenu (see next section) covers that. --- 4. Click‑Activated Sub‑Menu (Checkbox Hack) > Why a checkbox? > Without JavaScript, a hidden checkbox can maintain a persistent state (checked/unchecked) that you style with :checked selectors.html Services ▾ Service A Service B css /* Hide the checkbox visually but keep it in the DOM */ #toggle-services { position: absolute; left: -9999px; } /* When the checkbox is checked, show the submenu */ #toggle-services:checked + .menu__link--toggle + .submenu { opacity: 1; visibility: visible; transform: translateY(0); } /* Optional: rotate the arrow when open */ .menu__link--toggle::after { content: '▾'; display: inline-block; transition: transform .3s; } #toggle-services:checked + .menu__link--toggle::after { transform: rotate(180deg); } > **Keyboard‑only behavior** > Because the `` is a ``‑like link, clicking it toggles the checkbox, which in turn opens the submenu. `:focus-visible` on the label ensures that keyboard users see the focus ring. --- 5. Mega‑Menu with CSS Gridhtml Resources Docs Getting Started API Reference Community Events Forums css /* Mega‑menu container */ .mega-menu { position: absolute; left: 0; top: 100%; width: 600px; /* adjust as needed */ background: #fff; padding: 1rem; box-shadow: 0 6px 12px rgba(0,0,0,.15); opacity: 0; visibility: hidden; transform: translateY(10px); transition: opacity .25s ease, transform .25s ease; display: grid; grid-template-columns: repeat(2, 1fr); /* two columns, change for more */ gap: 1rem; } /* Reveal on hover/focus */ .menu__item--has-mega:hover > .mega-menu, .menu__item--has-mega:focus-within > .mega-menu { opacity: 1; visibility: visible; transform: translateY(0); } /* Column styling */ .mega-col { padding: .5rem; } .mega-heading { margin: 0 0 .5rem 0; font-size: 1rem; } .mega-link { display: block; padding: .25rem 0; color: #444; } .mega-link:hover, .mega-link:focus-visible { color: #0066ff; } > **Why CSS Grid?** > It gives you precise control over the layout of the mega‑menu, allowing multiple columns, nested grids, or responsive re‑flows. --- 6. Accessibility & ARIA | Element | ARIA | Why | |---------|------|-----| | `` | `role="navigation"` + `aria-label` | Announces the navigation region to screen readers. | | ` with sub‑menu | aria-haspopup="true" | Indicates the presence of a submenu. | | toggle | aria-expanded="true/false" | Communicates open state. Use CSS to set aria-expanded via content. | | Sub‑menu | role="menu" | Identifies the submenu as a menu list. | | Sub‑menu | role="menuitem" | Helps identify selectable items. | | Focus ring | outline + outline-offset | Visible focus indicator for keyboard users. | | Hidden content for screen readers | .hidden-visually` | Keep non‑visual helpers out of sight but still announced. | Implementationcss / Add ARIA attributes via CSS (optional) / .menu__item--has-submenu > .submenu { role: menu; } .menuitem--has-submenu > .submenu > .menulink { role: menuitem; } / Focus styling with focus-visible (modern) / .menu__link:focus-visible { outline: 2px solid #0066ff; outline-offset: 2px; } Testing Checklist Tab order – :focus-visible should appear on all interactive links.Screen reader – Use NVDA / VoiceOver to confirm the navigation region and submenu announcements.Keyboard – Tab + Enter or Space should open/collapse sub‑menus. --- 7. Responsive Breakpoints If you need the menu to stack vertically on mobile:css @media (max-width: 768px) { .primary-nav .menu { flex-direction: column; } .submenu, .mega-menu { position: relative; width: 100%; box-shadow: none; } .mega-menu { width: auto; } } --- 8. Browser Compatibility Checklist | Feature | Supported in | |---------|--------------| | `flex` & `box-sizing` | IE 10+, all modern browsers | | `:hover`, `:focus-within`, `:focus-visible` | Safari 12+, Chrome 80+, Edge 79+, Firefox 79+, IE 11 has `:focus` only | | `:checked` selector | IE 10+ | | CSS Grid | IE 11 has limited support (no `gap`); Chrome 57+, Edge 16+, Firefox 52+, Safari 10.1+ | | `box-shadow`, `transform` | All modern browsers | > **Polyfills** > If you need to support IE 11 and older, you can add the following polyfills or fallback CSS:html --- 9. Performance Tips | Tip | Rationale | |-----|-----------| | Use `will-change: opacity, transform` on sub‑menus | Signals to the browser to optimize compositing layers. | | Limit the depth of sub‑menus | Too many nested absolute positions can degrade rendering. | | Avoid heavy box shadows on many menus | Reduce overdraw for low‑power devices. |css .submenu, .mega-menu { will-change: opacity, transform; } ``` --- 10. Common Pitfalls & Debugging | Symptom | Likely Cause | Fix | |---------|--------------|-----| | Sub‑menu not showing on hover | `z-index` of parent `` too low | Increase `z-index` or remove `overflow: hidden` from parent containers | | Click‑submenu remains open after page navigation | Navigation link inside submenu triggers a new page | Ensure submenu links do not reload the same page; use `href="#"` or proper navigation | | Keyboard focus ring missing | `outline` removed by global reset | Add `outline` rules specifically for `.menu__link:focus-visible` | | Mega‑menu appears too wide on mobile | `width: 600px` fixed | Use `max-width: 100vw;` or adjust with media queries | --- 11. Final Thoughts No JavaScript needed – All interactions are handled by CSS pseudo‑classes and the checkbox hack.Progressive Enhancement – The base flex‑row menu works everywhere.Accessibility first – Proper ARIA roles and keyboard focus handling ensure the navigation is usable for all users.Performance – Minimal reflows, CSS transitions, and avoiding heavy DOM changes keep the UI snappy. Happy coding! 🎉 --- Feel free to adapt the naming conventions (`menu__link`, `mega-link`, etc.) to fit your project's naming scheme. If you need to add more columns to the mega‑menu, just update the `grid-template-columns` value accordingly.
No comments yet. Be the first to comment!