Today’s resource is a simple, handy snippet: a secondary navigation that slides down, replacing the main navigation links.

This approach can be an alternative to a standard dropdown menu, in particular if you want to emphasise more the sub navigation. Besides you can easily customize the snippet and use the slide in panel for a search box instead, or a login form - just to give you a couple of ideas.

Creating the structure

The HTML is structured in 2 main elements: an <header> wrapping the main navigation, and a <main> containing the page content.

The main navigation is composed of 2 nested unordered lists, semantically wrapped in a <nav> element.

<header> <div class="cd-logo"><a href="#0"><img src="img/cd-logo.svg" alt="Logo"></a></div> <nav class="cd-main-nav-wrapper"> <ul class="cd-main-nav"> <li><a href="#0">About</a></li> <!-- other list items here --> <li> <a href="#0" class="cd-subnav-trigger"><span>Categories</span></a> <ul> <li class="go-back"><a href="#0">Menu</a></li> <li><a href="#0">Category 1</a></li> <!-- other list items here --> </ul> </li> </ul> </nav> <a href="#0" class="cd-nav-trigger">Menu<span></span></a> </header> <main class="cd-main-content"> <!-- main content here --> </main>

Adding style

On small devices, the main navigation is on the right side, hidden by default; when user clicks the menu icon, the <main> and <header> elements translate to the left ( nav-is-visible class is applied) to reveal the navigation.

When user clicks the .cd-subnav-trigger , the main navigation is pushed to the left and replaced by the secondary navigation.

header.nav-is-visible { transform: translateX(-260px); } .cd-main-content.nav-is-visible { transform: translateX(-260px); } .cd-main-nav { position: fixed; top: 0; right: 0; width: 260px; visibility: hidden; } .cd-main-nav.nav-is-visible { visibility: visible; } .cd-main-nav li ul { position: absolute; top: 0; left: 0; width: 100%; transform: translateX(260px); } .cd-main-nav.moves-out > li > a { /* push the navigation items to the left - and lower down opacity - when secondary nav slides in */ transform: translateX(-100%); opacity: 0; } .cd-main-nav.moves-out > li > ul { /* reveal secondary nav */ transform: translateX(0); }

On desktop devices (viewport width more than 1024px), the secondary navigation is placed on top of the header (outside the viewport) and slides in covering the main navigation. We assigned a higher z-index to the .cd-logo and .cd-subnav-trigger so that they remain visible after the sub navigation has slided in.

Besides, we assigned the sub navigation the same padding as the .cd-main-nav and inserted a .placeholder element as last list item occupying the same space of the .cd-subnav-trigger : this way we make sure the sub navigation list items don't cover both the logo and the .cd-subnav-trigger .

@media only screen and (min-width: 1024px) { .cd-main-nav { height: 80px; /* padding left = logo size + logo left position*/ padding: 0 5% 0 calc(5% + 124px); text-align: right; } .cd-main-nav li ul { height: 80px; background-color: #7e4d7e; /* padding left = logo size + logo left position*/ padding: 0 5% 0 calc(5% + 124px); transform: translateY(-80px); transition: transform 0.3s 0.2s; } .cd-main-nav li ul li { opacity: 0; transform: translateY(-20px); transition: transform 0.3s 0s, opacity 0.3s 0s; } .cd-main-nav .placeholder { /* never visible or clickable- it is used to take up the same space as the .cd-subnav-trigger */ display: block; visibility: hidden; opacity: 0; pointer-event: none; } .cd-main-nav.moves-out > li > ul { transition: transform 0.3s; transform: translateY(0); } .cd-main-nav.moves-out > li ul li { opacity: 1; transform: translateY(0); transition: transform 0.3s 0.2s, opacity 0.3s 0.2s; } }

Events handling