Learn flexbox by building an awesome navbar
The traditional layout design techniques in website development has been bothering web designers for long. Many websites are still build using table layout and maintaining such websites is a tedious task. In modern times, an important point for every web developer to keep in mind is that the web page they are building must be mobile responsive. It should be able to adapt different screen sizes and achieving that using tables is not easy.
Lets learn a new feature called flexbox, introduced in CSS3 which is more powerful than tables and allows us to build responsive web pages much easily. PS: Flexbox is not necessary to build responsive website its just another feature introduced in CSS3. So, lets start by building a responsive navbar, one of the most important part of any web page.
Let’s jump right into coding -
index.html
<nav class="navbar">
<div class="brand"><img src="logo.png"></div>
<div class="toggle">
<i class="fas fa-bars"></i>
</div>
<div class="nav-item">
<div class="tab"><a href="#">Home</a></div>
<div class="tab"><a href="#">About</a></div>
<div class="tab"><a href="#">Contact</a></div>
</div>
</nav>
Result (without css) -
A typical navbar is mainly built using three components — brand, toggle and a menu. Brand is where a logo sits. Menu is the place where you can place links to other pages or a search form. Toggle is hidden for large screens and is visible only in small screens. A common behaviour associated with toggle is on clicking it, the menu will get displayed or hidden.
Now lets break down the Html code and add css properties to each of them to understand how each part is built.
index.html
<nav class="navbar"></nav>
style.css
.navbar {
padding: 6px 12px;
border-bottom: 1px solid #d9d9d9;
display: flex;
align-items: center;
}
The .navbar
div is the main container for the header. We are using display:flex;
to turn this container into a flexbox andalign-items: center;
is used to align them to the center vertically. This property works only when the container is a flexbox. To understand more about this property click here. We’ll see about this later in the article.
Now, lets add all the three containers to the navbar.
index.html
<nav class="navbar">
<div class="brand"></div>
<div class="toggle">
</div>
<div class="nav-item">
</div>
</nav>
style.css
.navbar {
padding: 6px 12px;
border-bottom: 1px solid #d9d9d9;
display: flex;
align-items: center;
}.brand {
padding: 4px 0;
}.toggle {
display: none;
padding: 20px 10px;
}.nav-item {
flex: 1;
display: flex;
justify-content: flex-end;
}
The .toggle
has display: none;
because it is hidden initially and visible only for mobile screens. We’ll come to that later.
Another important thing to note here is that .nav-item
has flex: 1;
which takes up the entire empty space between .brand
and .nav-item
. One thing which might confuse you is that, why does it take the space only in the left. To answer this question, you will have to look at another property below it justify-content: flex-end;
which aligns all the items inside the .nav-item
container, which itself is a flexbox, to the right end. This property aligns horizontally just like align-items
we saw previously aligns vertically. But, this is not always the case. There can be cases when their behaviour gets swapped. Well it happens when the main axis and cross axis are swapped because of a property called flex-direction
. To read more about this concept click here.
These are some important concepts of a flexbox. Please read through the paragraph again if you don’t understand comment in the section at the end.
Now lets add all the child elements of each container. A logo image inside .brand
, a bars icon inside .toggle
and few links inside .nav-item
.
index.html
<nav class="navbar">
<div class="brand"><img src="logo.png"></div>
<div class="toggle">
<i class="fas fa-bars"></i>
</div>
<div class="nav-item">
<div class="tab"><a href="#">Home</a></div>
<div class="tab"><a href="#">About</a></div>
<div class="tab"><a href="#">Contact</a></div>
</div>
</nav>
style.css
.navbar {
padding: 6px 12px;
border-bottom: 1px solid #d9d9d9;
display: flex;
align-items: center;
}.brand {
padding: 4px 0;
}.toggle {
display: none;
padding: 20px 10px;
}.nav-item {
order: 1;
flex: 1;
display: flex;
justify-content: flex-end;
}.nav-item > .tab {
padding: 8px;
}.nav-item .tab a {
text-decoration: none;
color: black;
}.nav-item .tab a:hover {
color: red;
}.show {
display: inline-block !important;
}@media only screen and (max-width: 768px) {
.navbar {
flex-direction: column;
align-items: flex-start;
}
.toggle {
align-self: flex-end;
position: absolute;
display: initial;
}
.nav-item {
flex-direction: column;
display: none;
}
}
There are few things to notice here. .toggle
container is made visible for mobile screens and position: absolute;
is used to align it. We cannot use the general flex align properties like other containers because if you notice that we have also added flex-direction: column;
to parent container .navbar
which swaps the main axis and cross axis. We had learned about these axises previously and from that we can infer that on changing the .flex-direction
the alignment properties also get swapped. So, when we change the flex-direction
to column
the align-items: center;
property which we had applied before for aligning items vertically will now align those items horizontally. To understand why we had to swap the axises, I’ll give you a hint, we want the menu to get displayed below the brand container and it should be visible only when toggle is clicked. Remember, I had added display: none;
to the .nav-item
inside the media query to hide it in mobile screens and display it only when the toggle button is clicked.
Before I jump into how the .nav-item
is getting toggled on click. There is an important thing to notice, .navbar
and .nav-item
both have display: flex;
because both have children and they both need to behave like flexbox each. Making.navbar
a flexbox does not make.nav-item
one, it only makes the immediate children flex items.
To add a toggling functionality, I have created a class in style.css called .show
which when added to any container changes the display property of that container to inline-block. Also adding a little javascript to add click event to the toggle container which adds this class to the .nav-item
.
(function () {
function classToggle() {
const navs = document.querySelectorAll('.nav-item');
navs.forEach(nav => nav.classList.toggle('show'));
}
document.querySelector('.toggle').addEventListener('click', classToggle);})();
Final Result -
Check out the source code of this article in my GitHub repository here -
— Thank You For Your Time