Building CSS dropdown menus is a classic struggle.
Hover states get stuck. Keyboard navigation breaks. Accessibility is forgotten. And if you don't position it right, the menu pushes all your page content down when it opens.
Let's fix the layout and the accessibility.
The Layout Problem
If your dropdown menu is in the normal document flow, making it visible (display: block) will expand the container's height. This pushes everything below it down.
To fix this, you need to take the dropdown out of the document flow using position: absolute.
/* The parent container must be relative */ .dropdown { position: relative; display: inline-block; } /* The menu is absolute and hidden by default */ .dropdown-content { display: none; position: absolute; top: 100%; /* Positions it right below the parent */ left: 0; z-index: 100; /* Ensures it sits on top of other elements */ background-color: white; box-shadow: 0 4px 6px rgba(0,0,0,0.1); } Because the dropdown is absolute, the browser ignores its space when calculating the layout of the rest of the page.
The Accessibility Problem
Using display: none and display: block on :hover works for mice, but it breaks for keyboard users and screen readers.
If a keyboard user tabs into the menu, the dropdown won't appear because they aren't hovering.
The Fix: :focus-within
Instead of just :hover, you should trigger the menu when the parent or any child receives focus.
.dropdown:hover .dropdown-content, .dropdown:focus-within .dropdown-content { display: block; } This ensures the menu stays open when a user tabs through the links.
Better yet: opacity and visibility
Using display: none means CSS transitions won't work (elements can't transition from display: none to display: block). It also removes the content from the accessibility tree entirely.
A smoother, more accessible approach is to toggle visibility and opacity:
.dropdown-content { position: absolute; visibility: hidden; opacity: 0; transition: opacity 0.2s, visibility 0.2s; } .dropdown:hover .dropdown-content, .dropdown:focus-within .dropdown-content { visibility: visible; opacity: 1; } Common Gotchas
- Z-Index: Dropdowns often appear behind other elements. Ensure the parent has a high enough
z-index. - Hover Gaps: If there's a gap between the button and the menu, moving the mouse across the gap will close the menu. Add a transparent padding to bridge the gap.
- Mobile: Hover doesn't exist on touch devices. You need a click-based JavaScript toggle for mobile menus.
The Visual Way
Writing multi-level CSS dropdowns, handling focus states, and ensuring accessibility is complex.
If you want to design, test, and export accessible multi-level CSS dropdown navigation menus visually, I built a free CSS Dropdown Menu Builder.
What it does:
- Visually designs multi-level dropdowns
- Handles hover and focus triggers
- Exports accessible CSS
100% client-side. Nothing uploaded.
What's the hardest part of building navigation menus for you? Let me know in the comments.


