🎉 Black Friday deal! 25% off your first year of CodyHouse Pro →

Full-Screen Pushing Navigation

Full-Screen Pushing Navigation

A full page menu, that replaces the current content by pushing it off the screen.

We recently came across the beautiful Hello Monday redesign.  One thing that captured our interest was the full size navigation: it replaces the current content entirely, by pushing it out. That inspired us to create todays nugget!

Here is a quick prototype of the final effect we put together:

pushing menu prototype

👋 A new version of this component is available. Download now →.

Creating the structure

The HTML is structured in 3 main elements: a <main> - containing the visible content, a div.cd-nav - wrapping the navigation, and a .cd-nav-trigger action button.

The .cd-nav is composed of 2 div elements, the first containing the navigation (.cd-nav__primary) and the second the contact info (.cd-nav__contact).

<div id="cd-nav" class="cd-nav">
  <div class="cd-nav__content">
    <div class="container max-width-sm">
      <h2 class="cd-nav__title">Navigation</h2>

      <div class="grid">
        <div class="[email protected]">
          <nav>
            <ul class="cd-nav__primary">
              <li><a href="#0" class="cd-nav__link cd-nav__link-selected">The team</a></li>
              <!-- list items here -->
            </ul>
          </nav>
        </div> <!-- [email protected] -->
        
        <div class="[email protected]">
          <address>
            <ul class="cd-nav__contact">
              <li><a href="mailto:[email protected]">[email protected]</a></li>
              <!-- other contact info here --> 
            </ul>
          </address>
        </div> <!-- [email protected] -->
      </div> <!-- .grid -->
    </div>
  </div> <!-- .cd-nav__content -->
</div> <!-- .cd-nav -->

The .cd-nav-trigger contains a span.cd-nav-trigger__icon, which is used to create the hamburger icon (the element itself is the central line, while its ::after and ::before pseudo-elements are used to create the upper and lower lines), and a svg element, which is used to create the loading circle.

<a href="#cd-nav" class="cd-nav-trigger js-cd-nav-trigger text-replace">
  Menu 
  <span class="cd-nav-trigger__icon" aria-hidden="true"></span>

  <svg viewBox="0 0 54 54" aria-hidden="true">
    <circle fill="transparent" stroke-width="1" cx="27" cy="27" r="25" stroke-dasharray="157 157" stroke-dashoffset="157"></circle>
  </svg>
</a>

Adding style

When user clicks the .cd-nav-trigger, the .nav-is-open class is added to the body: this class triggers the  hamburger icon animation and the menu entrance.

As for the hamburger icon, the animation can be divided into 3 different parts:

  • the transformation of the hamburger icon into an arrow: the .cd-nav-trigger__icon::after and .cd-nav-trigger__icon::before pseudo-elements are both rotated of 45/-45deg (using as transform-origin the right edge of the element) and their width is reduced to 50%;
  • the rotation of the entire .cd-nav-trigger__icon (180deg);
  • the circle loading effect: the stroke-dashoffset value of the circle element is set to zero (initially, it has a stroke-dasharray="157 157" and a stroke-dashoffset="157", where 157 is the circumference value).

CSS3 Transitions have been used to smooth the animation steps.

Here is a quick animation to show the whole process:

hamburger explained

.cd-nav-trigger {
  transition: transform 0.5s;

  circle {
    stroke: var(--cd-color-3);
    transition: stroke-dashoffset 0.4s; // circle border animation
  }
}

.nav-is-open .cd-nav-trigger {
  transform: rotate(180deg); // rotate trigger when navigation becomes visible

  circle {
    stroke-dashoffset: 0; // animate circle stroke
    transition: stroke-dashoffset 0.4s 0.3s;
  }
}

.cd-nav-trigger__icon { // menu icon created in CSS
  width: 22px;
  height: 2px;
  background-color: var(--color-white);
  transition: transform 0.3s;

  &::before, &:after { // upper and lower lines of the menu icon
    width: 100%;
    height: 100%; 
    transition: transform 0.5s, width 0.5s, top .3s;
  }

  &::before {
    transform-origin: right top;
    transform: translateY(-6px);
  }

  &::after {
    transform-origin: right bottom;
    transform: translateY(6px);
  }
}

.nav-is-open .cd-nav-trigger__icon::before,
.nav-is-open .cd-nav-trigger__icon::after { // animate arrow --> from menu to arrow
  width: 50%;
}

.nav-is-open .cd-nav-trigger__icon::before {
  transform: rotate(45deg);
}

.nav-is-open .cd-nav-trigger__icon::after {
  transform: rotate(-45deg);
}

For the menu entrance effect, the .cd-main__content and .cd-nav__content elements are both translated (along the X axis) by 100%. In order to create a more realistic pushing effect, we used a cubic bezier curve as transition timing function. This curve allows you to set 4 parameters (the curve control points) to create the optimal acceleration curve for the property that changes during your transition.

There are tools (like cubic-bezier.com) which allows you to customize your curve and preview the effect before using it into your code (you can also easily export the final curve parameters).

Here is a quick animation to show you the difference between a custom cubic-bezier timing functions and a linear one:

cubic-bezier curve

Events handling

We used JavaScript to listen to the click event on the .cd-nav-trigger and add/remove the .nav-is-open class consequently.

Level up your CSS skills

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

✅ Project duplicated

✅ Project created

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