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:
👋 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:
.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:
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.