Sometimes you just want your website navigation to be bold. Design agencies, for example, use their portfolio to show off their skills and push a little usability standards.

Another good example is mobile apps: animated elements are key ingredients of the user experience. In this case a 3D menu can't just be fun. It has to be efficient.

Inspiration for this nugget came from Taasky, a to-do iOS app with a great side navigation - that you can see in action on dribbble.

⭐️ Icons: Nucleo, icon organizer & icon library

👋 Important: this experiment is built using the CodyHouse Framework.

Creating the structure

We created a <header> element to wrap the logo and the trigger for the rotating navigation ( .cd-header__nav-trigger ) and a <main> element to wrap the main content.

We used an unordered list for the navigation, semantically wrapped into a <nav> element. A span.cd-3d-nav__marker has been appended to the <nav> to create the marker for the selected item in the navigation.

<header class="cd-header container flex justify-between items-center"> <a href="#0" class="cd-logo"> <!-- logo here --> </a> <a href="#cd-3d-nav" class="cd-header__nav-trigger" aria-label="Toggle menu"> <span aria-hidden="true"></span> </a> </header> <main class="cd-main"> <!-- all your content here --> </main> <nav class="cd-3d-nav js-cd-3d-nav" id="cd-3d-nav"> <ul class="cd-3d-nav__list"> <li class="cd-3d-nav__item cd-3d-nav__item--selected"> <a href="#0"> <svg aria-hidden="true" class="icon icon--md"><g stroke="currentColor" stroke-width="2" fill="none"><path d="M12,6.6c1.2-0.5,2.6-0.8,4-0.8 c5.6,0,10.2,4.6,10.2,10.2"></path><path d="M5.8,16c0-1.4,0.3-2.8,0.8-4"></path><line x1="13.9" y1="13.9" x2="8.4" y2="8.4"></line> <circle cx="16" cy="16" r="15"></circle><circle cx="16" cy="16" r="3"></circle></svg> <span>Dashboard</span> </a> </li> <!-- other list items here --> </ul> <span class="cd-3d-nav__marker cd-3d-nav__marker--col-1" aria-hidden="true"></span> </nav>

Adding Style

To realise our animation, we used CSS3 Transformations applied to the <header> , <main> and <nav> elements.

Here is a quick preview to show you the animation process (.gif created in After Effects).

By default, the navigation ( .cd-3d-nav ) is hidden right above the viewport ( translateY(-100%) and visibility: hidden ), while the unordered list ( .cd-3d-nav__list ) is rotated ( rotateX(90deg) and transform-origin: bottom center ).

When user clicks the trigger element, the class .cd-main--is-translated is added to the <main> , .cd-header--is-translated to the <header> and .cd-3d-nav--is-visible to the <nav> . These classes translate the elements of a quantity equal to the navigation height, while the .cd-3d-nav__list is rotated back ( rotateX(0) ).

CSS3 Transitions have been used to achieve a smooth animation.

:root { /* nav */ --cd-nav-height: 80px; /* animation */ --cd-nav-animation: 0.5s; } .cd-header { transition: transform var(--cd-nav-animation); } .cd-header--is-translated { transform: translateY(var(--cd-nav-height)); } .cd-3d-nav { position: fixed; top: 0; left: 0; visibility: hidden; perspective: 1000px; /* enable a 3D-space for children elements */ transform: translateY(-100%); transition: transform var(--cd-nav-animation) 0s, visibility 0s var(--cd-nav-animation); } .cd-3d-nav--is-visible { visibility: visible; transform: translateY(0); transition: transform var(--cd-nav-animation) 0s, visibility var(--cd-nav-animation) 0s; } .cd-3d-nav__list { transform-origin: center bottom; transform: rotateX(90deg); transition: transform var(--cd-nav-animation); } .cd-3d-nav--is-visible .cd-3d-nav__list { transform: translateZ(0); } .cd-main { transition: transform var(--cd-nav-animation); } .cd-main--is-translated { transform: translateY(var(--cd-nav-height)); }

The .cd-3d-nav__marker element has been used to create the marker for the selected navigation item (the <span> is the bottom line, while its ::before pseudo-element is the triangle).

In order to change the marker color, we defined the .cd-3d-nav__marker--col-n classes (one for each navigation item). These classes change the color and the background-color of the .cd-3d-nav__marker .

.cd-3d-nav__marker--col-1 { /* these are the colors of the marker - line + arrow */ color: var(--cd-color-2); background-color: var(--cd-color-2); } .cd-3d-nav__marker--col-2 { color: var(--cd-color-3); background-color: var(--cd-color-3); } /* other classes here */

Events Handling

We used JavaScript to toggle the .cd-header--is-translated / .cd-main--is-translated / .cd-3d-nav--is-visible classes when user clicks the navigation trigger.