Go to homepage

Projects /

3D Rotating Navigation

A 3D rotating navigation, powered by CSS transformations.

3D Rotating Navigation
Check our new component library →

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 href="#cd-3d-nav" class="cd-header__nav-trigger" aria-label="Toggle menu">
    <span aria-hidden="true"></span>

<main class="cd-main">
  <!-- all your content here -->

<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>

    <!-- other list items here -->

  <span class="cd-3d-nav__marker cd-3d-nav__marker--col-1" aria-hidden="true"></span> 

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.

Besides, when user selects one of the navigation list item, the left position of the span.cd-3d-nav__marker is changed so that it is aligned with the selected element, and the proper .cd-3d-nav__marker--col-n class is added (to change its background color).

Project duplicated

Project created

Globals imported

There was an error while trying to export your project. Please try again or contact us.