Go to homepage

Projects /

Full-Screen Pushing Navigation

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

Full-Screen Pushing Navigation
Check our new component library →

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="col-6@md">
          <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> <!-- .col-6@md -->
        
        <div class="col-6@md">
          <address>
            <ul class="cd-nav__contact">
              <li><a href="mailto:[email protected]">[email protected]</a></li>
              <!-- other contact info here --> 
            </ul>
          </address>
        </div> <!-- .col-6@md -->
      </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.

Project duplicated

Project created

Globals imported

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