I created this menu at work, when we wanted to have two menus but just one off-canvas navigation after the collapse. The idea was to combine an off-canvas menu with a classic navbar and then merge them into one separate off-canvas navigation on the collapse. Suprisingly, this proved to be not as easy as I initially had thought. But it was still achieved in the end, here you’ll see how.
See the Pen Two Menus, One responsive Off-Canvas by Myri (@mynimi) on CodePen.
Markup
We start with general markup. As already said in another tutorial I usually place my menus within a header so that’s what I did here as well. Then we have one container for both menus and each menu in a separate container with a list inside, since this is a dropdown. The toggle links to open the off canvas navs as well as the triangles to toggle the sub menues are going to be added via jQuery. I wanted the main menu to be aligned on the right and the toggle button on the left. To achieve that I had my toggle in a separate ul with the class first
and the main menu in a list with the class second
Markup in Jade
header
.menu-container
nav.off-canvas-menu
ul
li
a(href="#") Tasum
li
a(href="#") Aldpol
li.menu-item-has-children
a(href="#") Oughw
ul.sub-menu
li
a(href="#") Shyidra
li
a(href="#") Randel
li
a(href="#") Ia'usk
// /.sub-menu
li
a(href="#") Swaimim
// /ul
// /.off-canvas-menu
nav.main-menu
ul.second
li
a(href="#") Smedgone
li
a(href="#") Aotaliope
li.menu-item-has-children
a(href="#") Rothiope
ul.sub-menu
li
a(href="#") Delirious Lyric
li
a(href="#") Cleliopyte
li
a(href="#") Xioeleia
// /.sub-menu
li
a(href="#") Iorireto
// /ul
// /.main-menu
// /.menu-container
// /header
And the compiled HTML of that:
<header>
<div class="menu-container">
<nav class="off-canvas-menu">
<ul>
<li><a href="#">Tasum</a>
</li>
<li><a href="#">Aldpol</a>
</li>
<li class="menu-item-has-children"><a href="#">Oughw</a>
<ul class="sub-menu">
<li><a href="#">Shyidra</a>
</li>
<li><a href="#">Randel</a>
</li>
<li><a href="#">Ia'usk</a>
</li>
</ul>
<!-- /.sub-menu-->
</li>
<li><a href="#">Swaimim</a>
</li>
</ul>
<!-- /ul-->
</nav>
<!-- /.off-canvas-menu-->
<nav class="main-menu">
<ul class="second">
<li><a href="#">Smedgone</a>
</li>
<li><a href="#">Aotaliope</a>
</li>
<li class="menu-item-has-children"><a href="#">Rothiope</a>
<ul class="sub-menu">
<li><a href="#">Delirious Lyric</a>
</li>
<li><a href="#">Cleliopyte</a>
</li>
<li><a href="#">Xioeleia</a>
</li>
</ul>
<!-- /.sub-menu-->
</li>
<li><a href="#">Iorireto </a>
</li>
</ul>
<!-- /ul-->
</nav>
<!-- /.main-menu-->
</div>
<!-- /.menu-container-->
</header>
<!-- /header-->
jQuery
We will work on toggles with jQuery. So add jQuery before you add the following script
$(document).ready(function() {
var offCanvasToggle = 'toggle-link-off-canvas',
mainToggle = 'toggle-link',
close = 'toggle-link-close';
// add toggle links
$('header').prepend('<span class="toggle ' + mainToggle + '">Menu</span>');
$('.menu-container').prepend('<span class="toggle ' + mainToggle + ' ' + close + '">close</span>');
$('.off-canvas-menu').prepend('<span class="toggle ' + offCanvasToggle + ' ' + close + '">close</span>');
$('.main-menu').prepend('<ul class="first"><li><span class="toggle ' + offCanvasToggle + '">Menu Off-Canvas</span></li></ul>');
// click functions for toggle links to toggle active classes on off-canvas
$('header .toggle-link').click(function() {
$('.menu-container').toggleClass('active');
});
$('header .toggle-link-off-canvas').click(function() {
$('.off-canvas-menu').toggleClass('active');
});
// add Element for caret to toggle sub-menus
$('.menu-item-has-children > a').wrap('<span class="parent"></span>');
$('.menu-container .parent').append('<span class="submenu-opener">open submenu</span>');
// toggling submenus
$('.menu-container .submenu-opener').click(function() {
$(this).toggleClass('sub-menu-is-open');
$(this).parent().next('.sub-menu').slideToggle();
});
});
As soon as that’s done, we can add the styles.
Styling
As always I will use Sass. I use variables for the settings so feel free to play around.
Comments will go a little more into detail what everything does
// SETTINGS
//-----------
// helper
//--------
// colors
$pink: #E9B4B3;
$pale-pink: #F2E4E1;
$coal: #1D2426;
$teal: #35565D;
$grass: #8AB283;
// shortcuts
$noborder: 0 solid transparent;
// variable definitions
//----------------------
$menu-collapse: 610px;
$a_color: $pale-pink;
$a_color_hover: $pink;
$header_bg: $grass;
$off-canvas_bg: $teal;
$main_menu_bg: $coal;
// FUNCTIONS
//-----------
// squareroot
@function sqrt($r) {
$x0: 1;
$x1: $x0;
@for $i from 1 through 10 {
$x1: $x0 - ($x0 * $x0 - abs($r)) / (2 * $x0);
$x0: $x1;
}
@return $x1;
}
// MIXINS
//--------
// equilateral triangle
@mixin triangle_eqla($sl, $dir, $c) {
width: 0;
height: 0;
border-style: solid;
@if $dir == right {
border-color: transparent transparent transparent $c;
}
@if $dir == left {
border-color: transparent $c transparent transparent;
}
@if $dir == bottom or $dir == down {
border-color: $c transparent transparent transparent;
}
@if $dir == top or $dir == up {
border-color: transparent transparent $c transparent;
}
@if $dir == right or $dir == left {
border-width: ($sl/2) (sqrt(3)*($sl/2));
}
@if $dir == top or $dir == down or $dir == bottom or $dir == up {
border-width: (sqrt(3)*($sl/2)) ($sl/2);
}
}
// flexbox
@mixin flexbox($direction, $wrap, $justify, $align) {
display: flex;
flex-direction: $direction;
flex-wrap: $wrap;
justify-content: $justify;
align-items: $align;
}
// STYLING
//---------
// basic styles
body {
font: {
size: 16px;
weight: 400;
family: Roboto;
}
line-height: 1.5;
}
a {
color: $a_color;
text-decoration: none;
&:hover {
color: $a_color_hover;
cursor: pointer;
}
}
// main style
header {
position: fixed;
top: 0;
left: 0;
width: 100%;
background: $header_bg;
line-height: 2;
@media screen and (max-width: $menu-collapse){
@include flexbox(row, wrap, center, center);
}
// toggle link styling
.toggle {
@extend a;
padding: 6px;
}
.toggle-link-close {
position: absolute;
top: 0;
right: 0;
}
.toggle-link {
@media screen and (min-width: $menu-collapse + 1) {
display: none;
}
}
.toggle-link-off-canvas {
@media screen and (max-width: $menu-collapse) {
display: none;
}
}
}
// menu container, styles will be applied for the responsive version especially
.menu-container {
@media screen and (max-width: $menu-collapse) {
z-index: 100;
position: fixed;
top: 0;
left: -300px;
height: 100%;
overflow-y: auto;
background: $off-canvas_bg;
width: 300px;
box-sizing: border-box;
transition: .3s all ease;
transform: translate(0, 0);
&.active {
transform: translate(300px, 0);
}
}
// sub menu styles, are the same as with the off-canvas styling
.sub-menu {
border-top: 1px solid rgba($coal, .5);
border-bottom: 1px solid rgba($coal, .5);
background: lighten($off-canvas_bg, 5%);
display: none;
li {
a {
box-sizing: border-box;
@media screen and (max-width: $menu-collapse) {
padding-left: 25px;
}
}
}
}
// clickable triangle to toggle sub menu visibility
.parent {
@include flexbox(row, wrap, flex-start, center);
.submenu-opener {
font-size: 0;
position: relative;
width: 20px;
height: 20px;
transition: .6s all ease;
@media screen and (max-width: $menu-collapse) {
margin-left: 20px;
}
@media screen and (min-width: $menu-collapse + 1) {
margin-left: 5px;
}
&.sub-menu-is-open {
transform: rotate(-180deg);
}
&:after {
content: '';
@include triangle_eqla(10px, down, $a_color);
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -20%);
transition: .3s all ease;
}
&:hover {
cursor: pointer;
&:after {
border-color: $a_color_hover transparent transparent transparent;
}
}
}
}
}
// off-canvas navigation
.off-canvas-menu {
line-height: 2.5;
@media screen and (min-width: $menu-collapse + 1) {
z-index: 100;
position: fixed;
top: 0;
left: -300px;
height: 100%;
overflow-y: auto;
background: $off-canvas_bg;
width: 300px;
box-sizing: border-box;
transition: .3s all ease;
transform: translate(0, 0);
&.active {
transform: translate(300px, 0);
}
}
a {
padding: 0 10px;
}
}
// main menu for responsive and full version
.main-menu {
@media screen and (max-width: $menu-collapse) {
border-top: 1px solid darken($off-canvas_bg, 5%);
line-height: 2.5;
a {
padding: 0 10px;
}
}
@media screen and (min-width: $menu-collapse + 1) {
position: fixed;
width: 100%;
left: 0;
right: 0;
background: $main_menu_bg;
@include flexbox(row, wrap, space-between, center);
ul {
@include flexbox(row, wrap, flex-start, center);
li {
padding: 10px;
}
}
.sub-menu {
top: 100%;
position: absolute;
background: lighten($main_menu_bg, 5%);
}
}
}
And the compiled CSS of that:
body {
font-size: 16px;
font-weight: 400;
font-family: Roboto;
line-height: 1.5;
}
a, header .toggle {
color: #F2E4E1;
text-decoration: none;
}
a:hover, header .toggle:hover {
color: #E9B4B3;
cursor: pointer;
}
header {
position: fixed;
top: 0;
left: 0;
width: 100%;
background: #8AB283;
line-height: 2;
}
@media screen and (max-width: 610px) {
header {
display: -webkit-box;
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
-webkit-box-orient: horizontal;
-webkit-box-direction: normal;
-webkit-flex-direction: row;
-ms-flex-direction: row;
flex-direction: row;
-webkit-flex-wrap: wrap;
-ms-flex-wrap: wrap;
flex-wrap: wrap;
-webkit-box-pack: center;
-webkit-justify-content: center;
-ms-flex-pack: center;
justify-content: center;
-webkit-box-align: center;
-webkit-align-items: center;
-ms-flex-align: center;
align-items: center;
}
}
header .toggle {
padding: 6px;
}
header .toggle-link-close {
position: absolute;
top: 0;
right: 0;
}
@media screen and (min-width: 611px) {
header .toggle-link {
display: none;
}
}
@media screen and (max-width: 610px) {
header .toggle-link-off-canvas {
display: none;
}
}
@media screen and (max-width: 610px) {
.menu-container {
z-index: 100;
position: fixed;
top: 0;
left: -300px;
height: 100%;
overflow-y: auto;
background: #35565D;
width: 300px;
box-sizing: border-box;
-webkit-transition: .3s all ease;
transition: .3s all ease;
-webkit-transform: translate(0, 0);
-ms-transform: translate(0, 0);
transform: translate(0, 0);
}
.menu-container.active {
-webkit-transform: translate(300px, 0);
-ms-transform: translate(300px, 0);
transform: translate(300px, 0);
}
}
.menu-container .sub-menu {
border-top: 1px solid rgba(29, 36, 38, 0.5);
border-bottom: 1px solid rgba(29, 36, 38, 0.5);
background: #3e656d;
display: none;
}
.menu-container .sub-menu li a, .menu-container .sub-menu li header .toggle, header .menu-container .sub-menu li .toggle {
box-sizing: border-box;
}
@media screen and (max-width: 610px) {
.menu-container .sub-menu li a, .menu-container .sub-menu li header .toggle, header .menu-container .sub-menu li .toggle {
padding-left: 25px;
}
}
.menu-container .parent {
display: -webkit-box;
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
-webkit-box-orient: horizontal;
-webkit-box-direction: normal;
-webkit-flex-direction: row;
-ms-flex-direction: row;
flex-direction: row;
-webkit-flex-wrap: wrap;
-ms-flex-wrap: wrap;
flex-wrap: wrap;
-webkit-box-pack: start;
-webkit-justify-content: flex-start;
-ms-flex-pack: start;
justify-content: flex-start;
-webkit-box-align: center;
-webkit-align-items: center;
-ms-flex-align: center;
align-items: center;
}
.menu-container .parent .submenu-opener {
font-size: 0;
position: relative;
width: 20px;
height: 20px;
-webkit-transition: .6s all ease;
transition: .6s all ease;
}
@media screen and (max-width: 610px) {
.menu-container .parent .submenu-opener {
margin-left: 20px;
}
}
@media screen and (min-width: 611px) {
.menu-container .parent .submenu-opener {
margin-left: 5px;
}
}
.menu-container .parent .submenu-opener.sub-menu-is-open {
-webkit-transform: rotate(-180deg);
-ms-transform: rotate(-180deg);
transform: rotate(-180deg);
}
.menu-container .parent .submenu-opener:after {
content: '';
width: 0;
height: 0;
border-style: solid;
border-color: #F2E4E1 transparent transparent transparent;
border-width: 8.66025px 5px;
position: absolute;
top: 50%;
left: 50%;
-webkit-transform: translate(-50%, -20%);
-ms-transform: translate(-50%, -20%);
transform: translate(-50%, -20%);
-webkit-transition: .3s all ease;
transition: .3s all ease;
}
.menu-container .parent .submenu-opener:hover {
cursor: pointer;
}
.menu-container .parent .submenu-opener:hover:after {
border-color: #E9B4B3 transparent transparent transparent;
}
.off-canvas-menu {
line-height: 2.5;
}
@media screen and (min-width: 611px) {
.off-canvas-menu {
z-index: 100;
position: fixed;
top: 0;
left: -300px;
height: 100%;
overflow-y: auto;
background: #35565D;
width: 300px;
box-sizing: border-box;
-webkit-transition: .3s all ease;
transition: .3s all ease;
-webkit-transform: translate(0, 0);
-ms-transform: translate(0, 0);
transform: translate(0, 0);
}
.off-canvas-menu.active {
-webkit-transform: translate(300px, 0);
-ms-transform: translate(300px, 0);
transform: translate(300px, 0);
}
}
.off-canvas-menu a, .off-canvas-menu header .toggle, header .off-canvas-menu .toggle {
padding: 0 10px;
}
@media screen and (max-width: 610px) {
.main-menu {
border-top: 1px solid #2c474d;
line-height: 2.5;
}
.main-menu a, .main-menu header .toggle, header .main-menu .toggle {
padding: 0 10px;
}
}
@media screen and (min-width: 611px) {
.main-menu {
position: fixed;
width: 100%;
left: 0;
right: 0;
background: #1D2426;
display: -webkit-box;
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
-webkit-box-orient: horizontal;
-webkit-box-direction: normal;
-webkit-flex-direction: row;
-ms-flex-direction: row;
flex-direction: row;
-webkit-flex-wrap: wrap;
-ms-flex-wrap: wrap;
flex-wrap: wrap;
-webkit-box-pack: justify;
-webkit-justify-content: space-between;
-ms-flex-pack: justify;
justify-content: space-between;
-webkit-box-align: center;
-webkit-align-items: center;
-ms-flex-align: center;
align-items: center;
}
.main-menu ul {
display: -webkit-box;
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
-webkit-box-orient: horizontal;
-webkit-box-direction: normal;
-webkit-flex-direction: row;
-ms-flex-direction: row;
flex-direction: row;
-webkit-flex-wrap: wrap;
-ms-flex-wrap: wrap;
flex-wrap: wrap;
-webkit-box-pack: start;
-webkit-justify-content: flex-start;
-ms-flex-pack: start;
justify-content: flex-start;
-webkit-box-align: center;
-webkit-align-items: center;
-ms-flex-align: center;
align-items: center;
}
.main-menu ul li {
padding: 10px;
}
.main-menu .sub-menu {
top: 100%;
position: absolute;
background: #283234;
}
}
And that’s it.