Skip to main content

Two Menus, One Responsive Off-Canvas Navigation

two menus combined into one off-canvas nav

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

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

1
header
2
.menu-container
3
nav.off-canvas-menu
4
ul
5
li
6
a(href="#") Tasum
7
li
8
a(href="#") Aldpol
9
10
li.menu-item-has-children
11
a(href="#") Oughw
12
ul.sub-menu
13
li
14
a(href="#") Shyidra
15
li
16
a(href="#") Randel
17
li
18
a(href="#") Ia'usk
19
// /.sub-menu
20
21
li
22
a(href="#") Swaimim
23
// /ul
24
// /.off-canvas-menu
25
26
nav.main-menu
27
ul.second
28
li
29
a(href="#") Smedgone
30
li
31
a(href="#") Aotaliope
32
33
li.menu-item-has-children
34
a(href="#") Rothiope
35
ul.sub-menu
36
li
37
a(href="#") Delirious Lyric
38
li
39
a(href="#") Cleliopyte
40
li
41
a(href="#") Xioeleia
42
// /.sub-menu
43
44
li
45
a(href="#") Iorireto
46
// /ul
47
// /.main-menu
48
// /.menu-container
49
// /header

And the compiled HTML of that:

1
<header>
2
<div class="menu-container">
3
<nav class="off-canvas-menu">
4
<ul>
5
<li><a href="#">Tasum</a>
6
</li>
7
<li><a href="#">Aldpol</a>
8
</li>
9
<li class="menu-item-has-children"><a href="#">Oughw</a>
10
<ul class="sub-menu">
11
<li><a href="#">Shyidra</a>
12
</li>
13
<li><a href="#">Randel</a>
14
</li>
15
<li><a href="#">Ia'usk</a>
16
</li>
17
</ul>
18
<!-- /.sub-menu-->
19
</li>
20
<li><a href="#">Swaimim</a>
21
</li>
22
</ul>
23
<!-- /ul-->
24
</nav>
25
<!-- /.off-canvas-menu-->
26
<nav class="main-menu">
27
<ul class="second">
28
<li><a href="#">Smedgone</a>
29
</li>
30
<li><a href="#">Aotaliope</a>
31
</li>
32
<li class="menu-item-has-children"><a href="#">Rothiope</a>
33
<ul class="sub-menu">
34
<li><a href="#">Delirious Lyric</a>
35
</li>
36
<li><a href="#">Cleliopyte</a>
37
</li>
38
<li><a href="#">Xioeleia</a>
39
</li>
40
</ul>
41
<!-- /.sub-menu-->
42
</li>
43
<li><a href="#">Iorireto </a>
44
</li>
45
</ul>
46
<!-- /ul-->
47
</nav>
48
<!-- /.main-menu-->
49
</div>
50
<!-- /.menu-container-->
51
</header>
52
<!-- /header-->

jQuery

jQuery

We will work on toggles with jQuery. So add jQuery before you add the following script

1
$(document).ready(function() {
2
var offCanvasToggle = 'toggle-link-off-canvas',
3
mainToggle = 'toggle-link',
4
close = 'toggle-link-close';
5
6
// add toggle links
7
$('header').prepend('<span class="toggle ' + mainToggle + '">Menu</span>');
8
$('.menu-container').prepend('<span class="toggle ' + mainToggle + ' ' + close + '">close</span>');
9
$('.off-canvas-menu').prepend('<span class="toggle ' + offCanvasToggle + ' ' + close + '">close</span>');
10
$('.main-menu').prepend('<ul class="first"><li><span class="toggle ' + offCanvasToggle + '">Menu Off-Canvas</span></li></ul>');
11
12
// click functions for toggle links to toggle active classes on off-canvas
13
$('header .toggle-link').click(function() {
14
$('.menu-container').toggleClass('active');
15
});
16
17
$('header .toggle-link-off-canvas').click(function() {
18
$('.off-canvas-menu').toggleClass('active');
19
});
20
21
// add Element for caret to toggle sub-menus
22
$('.menu-item-has-children > a').wrap('<span class="parent"></span>');
23
$('.menu-container .parent').append('<span class="submenu-opener">open submenu</span>');
24
25
// toggling submenus
26
$('.menu-container .submenu-opener').click(function() {
27
$(this).toggleClass('sub-menu-is-open');
28
$(this).parent().next('.sub-menu').slideToggle();
29
});
30
});

As soon as that’s done, we can add the styles.

Styling

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

1
// SETTINGS
2
//-----------
3
4
// helper
5
//--------
6
7
// colors
8
$pink: #E9B4B3;
9
$pale-pink: #F2E4E1;
10
$coal: #1D2426;
11
$teal: #35565D;
12
$grass: #8AB283;
13
14
// shortcuts
15
$noborder: 0 solid transparent;
16
17
// variable definitions
18
//----------------------
19
$menu-collapse: 610px;
20
$a_color: $pale-pink;
21
$a_color_hover: $pink;
22
$header_bg: $grass;
23
$off-canvas_bg: $teal;
24
$main_menu_bg: $coal;
25
26
27
// FUNCTIONS
28
//-----------
29
30
// squareroot
31
@function sqrt($r) {
32
$x0: 1;
33
$x1: $x0;
34
@for $i from 1 through 10 {
35
$x1: $x0 - ($x0 * $x0 - abs($r)) / (2 * $x0);
36
$x0: $x1;
37
}
38
@return $x1;
39
}
40
41
// MIXINS
42
//--------
43
44
// equilateral triangle
45
@mixin triangle_eqla($sl, $dir, $c) {
46
width: 0;
47
height: 0;
48
border-style: solid;
49
50
@if $dir == right {
51
border-color: transparent transparent transparent $c;
52
}
53
@if $dir == left {
54
border-color: transparent $c transparent transparent;
55
}
56
@if $dir == bottom or $dir == down {
57
border-color: $c transparent transparent transparent;
58
}
59
@if $dir == top or $dir == up {
60
border-color: transparent transparent $c transparent;
61
}
62
@if $dir == right or $dir == left {
63
border-width: ($sl/2) (sqrt(3)*($sl/2));
64
}
65
@if $dir == top or $dir == down or $dir == bottom or $dir == up {
66
border-width: (sqrt(3)*($sl/2)) ($sl/2);
67
}
68
}
69
70
// flexbox
71
@mixin flexbox($direction, $wrap, $justify, $align) {
72
display: flex;
73
flex-direction: $direction;
74
flex-wrap: $wrap;
75
justify-content: $justify;
76
align-items: $align;
77
}
78
79
// STYLING
80
//---------
81
82
// basic styles
83
body {
84
font: {
85
size: 16px;
86
weight: 400;
87
family: Roboto;
88
}
89
line-height: 1.5;
90
}
91
92
a {
93
color: $a_color;
94
text-decoration: none;
95
&:hover {
96
color: $a_color_hover;
97
cursor: pointer;
98
}
99
}
100
101
// main style
102
header {
103
position: fixed;
104
top: 0;
105
left: 0;
106
width: 100%;
107
background: $header_bg;
108
line-height: 2;
109
110
@media screen and (max-width: $menu-collapse){
111
@include flexbox(row, wrap, center, center);
112
}
113
114
// toggle link styling
115
.toggle {
116
@extend a;
117
padding: 6px;
118
}
119
120
.toggle-link-close {
121
position: absolute;
122
top: 0;
123
right: 0;
124
}
125
126
.toggle-link {
127
@media screen and (min-width: $menu-collapse + 1) {
128
display: none;
129
}
130
}
131
132
.toggle-link-off-canvas {
133
@media screen and (max-width: $menu-collapse) {
134
display: none;
135
}
136
}
137
}
138
139
// menu container, styles will be applied for the responsive version especially
140
.menu-container {
141
@media screen and (max-width: $menu-collapse) {
142
z-index: 100;
143
position: fixed;
144
top: 0;
145
left: -300px;
146
height: 100%;
147
overflow-y: auto;
148
background: $off-canvas_bg;
149
width: 300px;
150
box-sizing: border-box;
151
transition: .3s all ease;
152
transform: translate(0, 0);
153
154
&.active {
155
transform: translate(300px, 0);
156
}
157
}
158
159
// sub menu styles, are the same as with the off-canvas styling
160
.sub-menu {
161
border-top: 1px solid rgba($coal, .5);
162
border-bottom: 1px solid rgba($coal, .5);
163
background: lighten($off-canvas_bg, 5%);
164
display: none;
165
166
li {
167
a {
168
box-sizing: border-box;
169
@media screen and (max-width: $menu-collapse) {
170
padding-left: 25px;
171
}
172
}
173
}
174
}
175
176
// clickable triangle to toggle sub menu visibility
177
.parent {
178
@include flexbox(row, wrap, flex-start, center);
179
180
.submenu-opener {
181
font-size: 0;
182
position: relative;
183
width: 20px;
184
height: 20px;
185
transition: .6s all ease;
186
187
@media screen and (max-width: $menu-collapse) {
188
margin-left: 20px;
189
}
190
191
@media screen and (min-width: $menu-collapse + 1) {
192
margin-left: 5px;
193
}
194
195
&.sub-menu-is-open {
196
transform: rotate(-180deg);
197
}
198
199
&:after {
200
content: '';
201
@include triangle_eqla(10px, down, $a_color);
202
position: absolute;
203
top: 50%;
204
left: 50%;
205
transform: translate(-50%, -20%);
206
transition: .3s all ease;
207
}
208
209
&:hover {
210
cursor: pointer;
211
212
&:after {
213
border-color: $a_color_hover transparent transparent transparent;
214
}
215
}
216
}
217
}
218
}
219
220
// off-canvas navigation
221
.off-canvas-menu {
222
line-height: 2.5;
223
224
@media screen and (min-width: $menu-collapse + 1) {
225
z-index: 100;
226
position: fixed;
227
top: 0;
228
left: -300px;
229
height: 100%;
230
overflow-y: auto;
231
background: $off-canvas_bg;
232
width: 300px;
233
box-sizing: border-box;
234
transition: .3s all ease;
235
transform: translate(0, 0);
236
237
&.active {
238
transform: translate(300px, 0);
239
}
240
}
241
242
a {
243
padding: 0 10px;
244
}
245
}
246
247
// main menu for responsive and full version
248
.main-menu {
249
@media screen and (max-width: $menu-collapse) {
250
border-top: 1px solid darken($off-canvas_bg, 5%);
251
line-height: 2.5;
252
253
a {
254
padding: 0 10px;
255
}
256
}
257
258
@media screen and (min-width: $menu-collapse + 1) {
259
position: fixed;
260
width: 100%;
261
left: 0;
262
right: 0;
263
background: $main_menu_bg;
264
@include flexbox(row, wrap, space-between, center);
265
266
ul {
267
@include flexbox(row, wrap, flex-start, center);
268
269
li {
270
padding: 10px;
271
}
272
}
273
274
.sub-menu {
275
top: 100%;
276
position: absolute;
277
background: lighten($main_menu_bg, 5%);
278
}
279
}
280
}

And the compiled CSS of that:

1
body {
2
font-size: 16px;
3
font-weight: 400;
4
font-family: Roboto;
5
line-height: 1.5;
6
}
7
8
a, header .toggle {
9
color: #F2E4E1;
10
text-decoration: none;
11
}
12
a:hover, header .toggle:hover {
13
color: #E9B4B3;
14
cursor: pointer;
15
}
16
17
header {
18
position: fixed;
19
top: 0;
20
left: 0;
21
width: 100%;
22
background: #8AB283;
23
line-height: 2;
24
}
25
@media screen and (max-width: 610px) {
26
header {
27
display: -webkit-box;
28
display: -webkit-flex;
29
display: -ms-flexbox;
30
display: flex;
31
-webkit-box-orient: horizontal;
32
-webkit-box-direction: normal;
33
-webkit-flex-direction: row;
34
-ms-flex-direction: row;
35
flex-direction: row;
36
-webkit-flex-wrap: wrap;
37
-ms-flex-wrap: wrap;
38
flex-wrap: wrap;
39
-webkit-box-pack: center;
40
-webkit-justify-content: center;
41
-ms-flex-pack: center;
42
justify-content: center;
43
-webkit-box-align: center;
44
-webkit-align-items: center;
45
-ms-flex-align: center;
46
align-items: center;
47
}
48
}
49
header .toggle {
50
padding: 6px;
51
}
52
header .toggle-link-close {
53
position: absolute;
54
top: 0;
55
right: 0;
56
}
57
@media screen and (min-width: 611px) {
58
header .toggle-link {
59
display: none;
60
}
61
}
62
@media screen and (max-width: 610px) {
63
header .toggle-link-off-canvas {
64
display: none;
65
}
66
}
67
68
@media screen and (max-width: 610px) {
69
.menu-container {
70
z-index: 100;
71
position: fixed;
72
top: 0;
73
left: -300px;
74
height: 100%;
75
overflow-y: auto;
76
background: #35565D;
77
width: 300px;
78
box-sizing: border-box;
79
-webkit-transition: .3s all ease;
80
transition: .3s all ease;
81
-webkit-transform: translate(0, 0);
82
-ms-transform: translate(0, 0);
83
transform: translate(0, 0);
84
}
85
.menu-container.active {
86
-webkit-transform: translate(300px, 0);
87
-ms-transform: translate(300px, 0);
88
transform: translate(300px, 0);
89
}
90
}
91
.menu-container .sub-menu {
92
border-top: 1px solid rgba(29, 36, 38, 0.5);
93
border-bottom: 1px solid rgba(29, 36, 38, 0.5);
94
background: #3e656d;
95
display: none;
96
}
97
.menu-container .sub-menu li a, .menu-container .sub-menu li header .toggle, header .menu-container .sub-menu li .toggle {
98
box-sizing: border-box;
99
}
100
@media screen and (max-width: 610px) {
101
.menu-container .sub-menu li a, .menu-container .sub-menu li header .toggle, header .menu-container .sub-menu li .toggle {
102
padding-left: 25px;
103
}
104
}
105
.menu-container .parent {
106
display: -webkit-box;
107
display: -webkit-flex;
108
display: -ms-flexbox;
109
display: flex;
110
-webkit-box-orient: horizontal;
111
-webkit-box-direction: normal;
112
-webkit-flex-direction: row;
113
-ms-flex-direction: row;
114
flex-direction: row;
115
-webkit-flex-wrap: wrap;
116
-ms-flex-wrap: wrap;
117
flex-wrap: wrap;
118
-webkit-box-pack: start;
119
-webkit-justify-content: flex-start;
120
-ms-flex-pack: start;
121
justify-content: flex-start;
122
-webkit-box-align: center;
123
-webkit-align-items: center;
124
-ms-flex-align: center;
125
align-items: center;
126
}
127
.menu-container .parent .submenu-opener {
128
font-size: 0;
129
position: relative;
130
width: 20px;
131
height: 20px;
132
-webkit-transition: .6s all ease;
133
transition: .6s all ease;
134
}
135
@media screen and (max-width: 610px) {
136
.menu-container .parent .submenu-opener {
137
margin-left: 20px;
138
}
139
}
140
@media screen and (min-width: 611px) {
141
.menu-container .parent .submenu-opener {
142
margin-left: 5px;
143
}
144
}
145
.menu-container .parent .submenu-opener.sub-menu-is-open {
146
-webkit-transform: rotate(-180deg);
147
-ms-transform: rotate(-180deg);
148
transform: rotate(-180deg);
149
}
150
.menu-container .parent .submenu-opener:after {
151
content: '';
152
width: 0;
153
height: 0;
154
border-style: solid;
155
border-color: #F2E4E1 transparent transparent transparent;
156
border-width: 8.66025px 5px;
157
position: absolute;
158
top: 50%;
159
left: 50%;
160
-webkit-transform: translate(-50%, -20%);
161
-ms-transform: translate(-50%, -20%);
162
transform: translate(-50%, -20%);
163
-webkit-transition: .3s all ease;
164
transition: .3s all ease;
165
}
166
.menu-container .parent .submenu-opener:hover {
167
cursor: pointer;
168
}
169
.menu-container .parent .submenu-opener:hover:after {
170
border-color: #E9B4B3 transparent transparent transparent;
171
}
172
173
.off-canvas-menu {
174
line-height: 2.5;
175
}
176
@media screen and (min-width: 611px) {
177
.off-canvas-menu {
178
z-index: 100;
179
position: fixed;
180
top: 0;
181
left: -300px;
182
height: 100%;
183
overflow-y: auto;
184
background: #35565D;
185
width: 300px;
186
box-sizing: border-box;
187
-webkit-transition: .3s all ease;
188
transition: .3s all ease;
189
-webkit-transform: translate(0, 0);
190
-ms-transform: translate(0, 0);
191
transform: translate(0, 0);
192
}
193
.off-canvas-menu.active {
194
-webkit-transform: translate(300px, 0);
195
-ms-transform: translate(300px, 0);
196
transform: translate(300px, 0);
197
}
198
}
199
.off-canvas-menu a, .off-canvas-menu header .toggle, header .off-canvas-menu .toggle {
200
padding: 0 10px;
201
}
202
203
@media screen and (max-width: 610px) {
204
.main-menu {
205
border-top: 1px solid #2c474d;
206
line-height: 2.5;
207
}
208
.main-menu a, .main-menu header .toggle, header .main-menu .toggle {
209
padding: 0 10px;
210
}
211
}
212
@media screen and (min-width: 611px) {
213
.main-menu {
214
position: fixed;
215
width: 100%;
216
left: 0;
217
right: 0;
218
background: #1D2426;
219
display: -webkit-box;
220
display: -webkit-flex;
221
display: -ms-flexbox;
222
display: flex;
223
-webkit-box-orient: horizontal;
224
-webkit-box-direction: normal;
225
-webkit-flex-direction: row;
226
-ms-flex-direction: row;
227
flex-direction: row;
228
-webkit-flex-wrap: wrap;
229
-ms-flex-wrap: wrap;
230
flex-wrap: wrap;
231
-webkit-box-pack: justify;
232
-webkit-justify-content: space-between;
233
-ms-flex-pack: justify;
234
justify-content: space-between;
235
-webkit-box-align: center;
236
-webkit-align-items: center;
237
-ms-flex-align: center;
238
align-items: center;
239
}
240
.main-menu ul {
241
display: -webkit-box;
242
display: -webkit-flex;
243
display: -ms-flexbox;
244
display: flex;
245
-webkit-box-orient: horizontal;
246
-webkit-box-direction: normal;
247
-webkit-flex-direction: row;
248
-ms-flex-direction: row;
249
flex-direction: row;
250
-webkit-flex-wrap: wrap;
251
-ms-flex-wrap: wrap;
252
flex-wrap: wrap;
253
-webkit-box-pack: start;
254
-webkit-justify-content: flex-start;
255
-ms-flex-pack: start;
256
justify-content: flex-start;
257
-webkit-box-align: center;
258
-webkit-align-items: center;
259
-ms-flex-align: center;
260
align-items: center;
261
}
262
.main-menu ul li {
263
padding: 10px;
264
}
265
.main-menu .sub-menu {
266
top: 100%;
267
position: absolute;
268
background: #283234;
269
}
270
}

And that’s it.

Search

Results will appear as you type