Skip to main content

Basic responsive menu (off-canvas with flexbox)

pretty much the easiest 1-Level-Menu ever

Menus. The first Menu I wrote was a list that was made looking like a navigation with CSS. I still use a lisst for a drop down menu. But since we are finally ready to use Flexbox, I have given up on lists and turned to a simpler markip. This navigation is written with flexbos and becomes off-canvas once it collapses.

See the Pen responsive 1-Level Menu by Myri (@mynimi) on CodePen.

I use Font-Awesome and jQuery here because I always have those in my projectrs. But you can create a menu like that, with CSS only. If you are interested in a tutorial, let me know.

Markup

Markup

Since I use my menus in the header area that’s what I did here as well, because I did not want my toggle link floating arount in the emptyness. There are two. One within the nav element, that I use to wrap the items and one within. They will toggle the off-canvas. So only used for that version.

And so that markup is written a little faster, I will use jade

1
header
2
a.toggle-link(href='#menu')
3
| <i class="fa fa-navicon"></i> Menu
4
nav.main-menu#menu
5
a.toggle-link(href='#menu')
6
i.fa.fa-close
7
each val in [1, 2, 3, 4, 5]
8
a(href='index'+val+'.html')= 'Item ' + val

This will result in the following HTML

1
<header>
2
<a href="#menu" class="toggle-link">
3
<i class="fa fa-navicon"></i> Menu
4
</a>
5
<nav id="menu" class="main-menu">
6
<a href="#menu" class="toggle-link">
7
<i class="fa fa-close"></i>
8
</a>
9
<a href="index1.html">Item 1</a>
10
<a href="index2.html">Item 2</a>
11
<a href="index3.html">Item 3</a>
12
<a href="index4.html">Item 4</a>
13
<a href="index5.html">Item 5</a>
14
</nav>
15
</header>

Styling

Styling

Styling is done with Flexbox. And Sass, because I will never write plain CSS again. Comments will explain a bit further.

1
// point at which menu turns to off-canvas
2
$menu_collapse: 500px;
3
4
// basic styling
5
body {
6
font: {
7
size: 22px;
8
weight: 300;
9
family: Roboto;
10
}
11
line-height: 1.8;
12
color: #333;
13
}
14
15
header{
16
width: 100%;
17
position: relative;
18
left: 0;
19
top: 0;
20
background: darken(white, 15%);
21
}
22
a {
23
text-decoration: none;
24
color: black;
25
transition: .3s;
26
&:hover {
27
color: lighten(black, 50%);
28
}
29
}
30
31
// menu style
32
.main-menu {
33
display: flex;
34
flex-wrap: wrap;
35
align-items: center;
36
37
// change the way links appear with flex-direction
38
39
// on a horizontal line in non-collapsed way
40
@media screen and (min-width: $menu_collapse) {
41
flex-direction: row;
42
justify-content: space-between;
43
max-width: 800px;
44
45
.toggle-link {
46
display: none;
47
}
48
}
49
50
// off-canvas look
51
@media screen and (max-width: $menu_collapse) {
52
// make links appear underneath each other
53
flex-direction: column;
54
justify-content: flex-start;
55
56
// off-canvas style, closed
57
background: darken(white, 10%);
58
z-index: 100;
59
width: 320px;
60
min-height: 100%;
61
position: fixed;
62
top: 0;
63
left: 0;
64
transition: .3s all linear;
65
box-sizing: border-box;
66
padding: 10px;
67
transform: translateX(-320px);
68
69
// off-canvas, open
70
&.active {
71
transform: translateX(0px);
72
}
73
74
// position "x" in the upper right-hand corner
75
.toggle-link {
76
align-self: flex-end;
77
}
78
}
79
}
80
81
// make toggle links visible if off-canvas menu is to be displayed
82
header {
83
.toggle-link {
84
@media screen and (min-width: $menu_collapse) {
85
display: none;
86
}
87
}
88
}

and that’s what the styles look like after sass and autoprefixer did their work

1
.main-menu {
2
display: -webkit-box;
3
display: -webkit-flex;
4
display: -ms-flexbox;
5
display: flex;
6
-webkit-flex-wrap: wrap;
7
-ms-flex-wrap: wrap;
8
flex-wrap: wrap;
9
-webkit-box-align: center;
10
-webkit-align-items: center;
11
-ms-flex-align: center;
12
align-items: center;
13
}
14
@media screen and (min-width: 500px) {
15
.main-menu {
16
-webkit-box-orient: horizontal;
17
-webkit-box-direction: normal;
18
-webkit-flex-direction: row;
19
-ms-flex-direction: row;
20
flex-direction: row;
21
-webkit-box-pack: justify;
22
-webkit-justify-content: space-between;
23
-ms-flex-pack: justify;
24
justify-content: space-between;
25
max-width: 800px;
26
}
27
.main-menu .toggle-link {
28
display: none;
29
}
30
}
31
@media screen and (max-width: 500px) {
32
.main-menu {
33
-webkit-box-orient: vertical;
34
-webkit-box-direction: normal;
35
-webkit-flex-direction: column;
36
-ms-flex-direction: column;
37
flex-direction: column;
38
-webkit-box-pack: start;
39
-webkit-justify-content: flex-start;
40
-ms-flex-pack: start;
41
justify-content: flex-start;
42
background: #e6e6e6;
43
z-index: 100;
44
width: 320px;
45
min-height: 100%;
46
position: fixed;
47
top: 0;
48
left: 0;
49
-webkit-transition: .3s all linear;
50
transition: .3s all linear;
51
box-sizing: border-box;
52
padding: 10px;
53
-webkit-transform: translateX(-320px);
54
-ms-transform: translateX(-320px);
55
transform: translateX(-320px);
56
}
57
.main-menu.active {
58
-webkit-transform: translateX(0px);
59
-ms-transform: translateX(0px);
60
transform: translateX(0px);
61
}
62
.main-menu .toggle-link {
63
-webkit-align-self: flex-end;
64
-ms-flex-item-align: end;
65
align-self: flex-end;
66
}
67
}
68
69
@media screen and (min-width: 500px) {
70
header .toggle-link {
71
display: none;
72
}
73
}

and a pinch of jQuery

and a pinch of jQuery

For the off-canvas to function, we will write a click event, that triggers an active class to display the menu or hide it.

1
$(document).ready(function () {
2
$(".toggle-link").click(function () {
3
$("#menu").toggleClass("active");
4
});
5
});

and that’s it. Super simple, really easy to customize.

Search

Results will appear as you type