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

Level up your CSS skills

Each month we email a 1-minute CSS tutorial to 20K developers

Awesome! We just sent you a confirmation link by email

Error - please try again or contact us

Your email address is already subscribed

Project duplicated

Project created

Globals imported

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