DEV Community

loading...
Cover image for How to Build a Mobile-friendly, Fully Responsive Website Navigation Using Tailwind CSS

How to Build a Mobile-friendly, Fully Responsive Website Navigation Using Tailwind CSS

Andy Griffiths
Web Developer / Graphic Designer - #JavaScript #nodejs #PHP #Laravel #HTML5 #CSS3 - Husband / Father
・8 min read

Your website’s navigation is probably the single most important element on your page - you’ve got to make sure you get it right.

Yes, writing captivating content for your website is important but this will all be in vain if your users can’t navigate to it.

What makes things even harder, is that you also have to consider the usability of your navigation on countless devices, screen sizes and resolutions.

Luckily for you, there are several techniques and best practices to follow that will help you master the UI and UX of your website’s navigation.

We’ll explore them in this article.

Check out the DEMO
Download the SOURCE CODE

So what are we building

We’re going to build a mobile-friendly, fully responsive navigation using Tailwind CSS that:

  • Works across all screen sizes
  • Uses little to no custom CSS
  • Implements simple vanilla JavaScript
  • Doesn’t repeat or duplicate elements
  • Gives you a great starting point for your own projects

The Code

I believe it would be beneficial from a learning perspective for you to read the rest of the tutorial. I also get that you may be busy and just need to implement the solution.

So here’s the completed code.

index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Navigation</title>
    <link rel="stylesheet" href="public/dist/styles.css">
</head>
<body>
    <h1 class="text-center my-10 text-4xl">Responsive Navigation</h1>
    <nav class="flex flex-col md:flex-row bg-gray-200 p-5">
        <div class="flex flex-wrap justify-between items-center">
            <div>
                Logo goes here...
            </div>
            <div class="burger md:hidden">
                <div class="bar1 h-1 w-7 my-1.5 bg-gray-800 duration-300"></div>
                <div class="bar2 h-1 w-7 my-1.5 bg-gray-800"></div>
                <div class="bar3 h-1 w-7 my-1.5 bg-gray-800 duration-300"></div>
            </div>
        </div>
        <ul class="links md:flex flex-col md:flex-row text-center w-full md:justify-around hidden">
            <li>
                <a href="#" class="block p-5">
                    Home
                </a>
            </li>
            <li>
                <a href="#" class="block p-5">
                    Services
                </a>
            </li>
            <li>
                <a href="#" class="block p-5">
                    About
                </a>
            </li>
            <li>
                <a href="#" class="block p-5">
                    Contact
                </a>
            </li>
            <li>
                <a href="#" class="block p-5">
                    Blog
                </a>
            </li>
        </ul>
    </nav>
    <script src="public/dist/script.js"></script>
</body>
</html>
Enter fullscreen mode Exit fullscreen mode

script.js

const burger = document.querySelector('.burger');
const links = document.querySelector('.links');
const bar1 = document.querySelector('.bar1');
const bar2 = document.querySelector('.bar2');
const bar3 = document.querySelector('.bar3');

burger.addEventListener('click', () => {
    links.classList.toggle('hidden');
    bar1.classList.toggle('transform');
    bar1.classList.toggle('translate-y-1.5'); 
    bar1.classList.toggle('-rotate-45');
    bar2.classList.toggle('hidden');
    bar3.classList.toggle('transform');
    bar3.classList.toggle('-translate-y-1');        
    bar3.classList.toggle('rotate-45');
});
Enter fullscreen mode Exit fullscreen mode

If you do have the time, then please read on...

Initial setup

As I’m sure you’ve guessed, we’re going to be using the amazing Tailwind CSS framework for all of our CSS styling in this project.

You could just include a link to their CDN but then you’re not going to benefit from all of the fantastic features.

So let’s include TailwInd CSS via NPM.

npm i tailwindcss@latest postcss@latest autoprefixer@latest postcss-cli

Once this has finished installing, we need to set up a couple more things before we can code our navigation.

Open the package.json file, as we need to add a couple of scripts to allow us to compile our Tailwind CSS later.

"build": "postcss ./src/styles.css -o ./public/dist/styles.css",
"prod": "NODE_ENV=production postcss ./src/styles.css -o ./public/dist/styles.css"
Enter fullscreen mode Exit fullscreen mode

In your terminal, run npx tailwindcss init -p to create our tailwind.config.js and postcss.config.js files, then open up the tailwind.config.js file and update darkMode to class.

Before we can compile our CSS, we need to create the source CSS file.

Create the src folder mkdir src then cd src in to the directory and create the CSS file touch styles.css.

Add the included to the styles.css file

@tailwind base;
@tailwind components;
@tailwind utilities;
Enter fullscreen mode Exit fullscreen mode

Then run npm run build. This should output our compiled styles to our public/dist/styles.css file.

HTML markup - the structure (& style)

Now we have included Tailwind CSS in our project and compiled the development bundle, it’s time to start writing the HTML markup.

If you’re already familiar with Tailwind CSS you’ll know that to style HTML elements, you add various ‘utility’ classes inline. This saves a lot of time writing custom CSS, speeding up development considerably.

First things first, let's get our 'boilerplate' set out.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Navigation</title>
</head>
<body>

</body>
</html>
Enter fullscreen mode Exit fullscreen mode

If you're using VS Code, you can automagically write the above code by hitting ! then tab.

You'll then need to add a link to your compiled styles.css in your head tag.

    ...
    <link rel="stylesheet" href="public/dist/styles.css">
</head>
Enter fullscreen mode Exit fullscreen mode

Next, within the body tag, let's add the HTML for the structure of the actual navigation.

<nav>
    <ul class="links">
        <li>
            <a href="#">
                Home
            </a>
        </li>
        <li>
            <a href="#">
                Services
            </a>
        </li>
        <li>
            <a href="#">
                About
            </a>
        </li>
        <li>
            <a href="#">
                Contact
            </a>
        </li>
        <li>
            <a href="#">
                Blog
            </a>
        </li>
    </ul>
</nav>
Enter fullscreen mode Exit fullscreen mode

The above code should be pretty self-explanatory but to recap - we create a nav tag and then inside we add an unordered list for our links, which is common convention for website navigations.

Next, let's use Tailwind's utility classes to add some styling as it's looking a little bit boring.

There are a few ways we could approach the layout of our navigation, in this case, we are going to use flexbox. This will give us all the tools we need to be able to respond to the various screen sizes we need to cater for.

Mobile web browsing overtook desktop web browsing several years ago, so it makes sense to build the navigation mobile-first. We'll concentrate on getting this to work on mobile (smaller screens) and then adapt this to work on desktops later.

Most mobile devices have limited horizontal real estate so it's common practice to arrange your navigation's links beneath one another in a vertical alignment. We will use Tailwind's flexbox utility classes to achieve this.

<nav class="flex flex-col md:flex-row bg-gray-200 p-5">
    <ul class="links flex flex-col text-center">
        ...
    </ul>
</nav>
Enter fullscreen mode Exit fullscreen mode

What have we just done? We set the ul as flexbox with flex and then positioned the links in a column so they stack with flex-col then finally centred the text with text-center.

Because mobile devices don't have hover, it's really important each link has enough spacing so the user can easily press the desired option. Let's add some padding to each link to achieve this.

<li>
    <a href="#" class="block p-5">
      Home
  </a>
</li>
Enter fullscreen mode Exit fullscreen mode

This is starting to look and work a lot better now. It's not ideal having the links taking up the entire vertical space of the screen though. We need a way to hide these when not in use.

To achieve this, we'll create a custom burger style button that will use some basic vanilla JavaScript to hide and show the links as they're required. Let's add the basic HTML structure.

<div>
    <div>
        <div></div>
        <div></div>
        <div></div>
    </div>
</div>
<ul class="links flex flex-col text-center">
    ...
</ul>
Enter fullscreen mode Exit fullscreen mode

One of the goals whilst building this navigation, was to use little to no custom CSS if possible. With this in mind, we're now going to use more of Tailwind's CSS utility classes to build the custom burger menu icon.

<div class="flex flex-wrap justify-between items-center">
    <div class="burger">
        <div class="h-1 w-7 my-1.5 bg-gray-800"></div>
        <div class="h-1 w-7 my-1.5 bg-gray-800"></div>
        <div class="h-1 w-7 my-1.5 bg-gray-800"></div>
    </div>
</div>
Enter fullscreen mode Exit fullscreen mode

The navigation is now laid out in a sensible way for smaller devices such as mobiles. However, on desktop, the links are taking up too much of the space and would be better placed horizontally. Let's fix that now.

Also, the burger menu is not required on bigger screens, so we will hide that too.

Tailwind conveniently provides responsive utility modifiers classes that lets us target various screen sizes. In our example, we'll set the links to align next to each other horizontally with flex-row and hide the burger with the hidden class. Notice the md: modifier pre-fixed to the classes.

    <div>    
        <div class="burger md:hidden">
        <div class="h-1 w-7 my-1.5 bg-gray-800"></div>
        <div class="h-1 w-7 my-1.5 bg-gray-800"></div>
        <div class="h-1 w-7 my-1.5 bg-gray-800"></div>
    </div>
</div>
<ul class="links md:flex flex-col md:flex-row text-center w-full md:justify-around">
Enter fullscreen mode Exit fullscreen mode

Before we tackle the JavaScript to hide and show the links on mobile, I want to add a section where we can add our logo or site name. So let's update our HTML markup.

<nav class="flex flex-col md:flex-row bg-gray-200 p-5">
    <div>
        <div>
            Logo goes here...
        </div>
        <div class="burger md:hidden">
            <div class="bar1 h-1 w-7 my-1.5 bg-gray-800"></div>
            <div class="bar2 h-1 w-7 my-1.5 bg-gray-800"></div>
            <div class="bar3 h-1 w-7 my-1.5 bg-gray-800"></div>
        </div>
    </div>
    <ul class="links md:flex flex-col md:flex-row text-center w-full md:justify-around hidden">
Enter fullscreen mode Exit fullscreen mode

You'll notice the links have now disappeared on mobile, this is in preparation for our JavaScript. We'll write that now.

In the public/dist directory create a new file called script.js and link in your HTML file just before the closing body tag.

    <script src="public/dist/script.js"></script>
</body>
Enter fullscreen mode Exit fullscreen mode

Open the script.js file and add the following code.

const burger = document.querySelector('.burger');
const links = document.querySelector('.links');

burger.addEventListener('click', () => {
    links.classList.toggle('hidden');
});
Enter fullscreen mode Exit fullscreen mode

You should now have a fully functional mobile-friendly, responsive navigation.

To add the cherry on top, let's add an animation to the burger icon.

Update your HTML to...

<div class="burger md:hidden">
    <div class="bar1 h-1 w-7 my-1.5 bg-gray-800 duration-300"></div>
    <div class="bar2 h-1 w-7 my-1.5 bg-gray-800"></div>
    <div class="bar3 h-1 w-7 my-1.5 bg-gray-800 duration-300"></div>
</div>
Enter fullscreen mode Exit fullscreen mode

Then update your script.js file to...

const burger = document.querySelector('.burger');
const links = document.querySelector('.links');
const bar1 = document.querySelector('.bar1');
const bar2 = document.querySelector('.bar2');
const bar3 = document.querySelector('.bar3');

burger.addEventListener('click', () => {
    links.classList.toggle('hidden');
    bar1.classList.toggle('transform');
    bar1.classList.toggle('translate-y-1.5'); 
    bar1.classList.toggle('-rotate-45');
    bar2.classList.toggle('hidden');
    bar3.classList.toggle('transform');
    bar3.classList.toggle('-translate-y-1');        
    bar3.classList.toggle('rotate-45');
});
Enter fullscreen mode Exit fullscreen mode

That wraps up this tutorial.

If you enjoyed the tutorial, please make sure you follow me here on dev.to and Twitter so you don’t miss out when new tutorials are available.

Discussion (0)