My WebDev Notes: Fullscreen overlay navigation
Tags: html, css, javascript
Published: 2020-04-13 12:07:18

---
title: My WebDev Notes: Fullscreen overlay navigation
published: true
description: A detailed experiment on creating fullscreen overlay navigation using css, html, and JavaScript
tags: html, css, javascript
series: My WebDev Notes
---

> <b>Check the overlay navigation online: https://ziizium.github.io/my-webdev-notes/fullscreen-navigation/</b>

##__Introduction__

Navigation is an essential part of every website and on a normal day, it will contain links to other resources on a website. You will find them in various design and layout based on the website.

This experiment, as the title indicates is about creating a _fullscreen overlay_ navigation using HTML, CSS, and JavaScript. HTML for the markup, CSS for the presentation and JavaScript for the behavior.

Some CSS properties are not supported by all browsers and we will have to do some testing before throwing some code at the browser. Luckily, CSS provides a way to do this via the `@supports` feature query.

In addition, the overlay navigation will be hidden from view by default and will be available on mobile _viewport_ via JavaScript. But we should know that some users might have JavaScript turned off in their browser therefore, we have to make the navigation accessible when the user has JavaScript turned off.

The problem is: How can we make the navigation accessible to users with JavaScript turned off?.

I am pretty sure there are many ways to solve a problem but the solution I came up with might not be _fancy_. Here is what I did.

I created two stylesheets, one for browsers with JavaScript turned off and the other for a browser with JavaScript enabled. The stylesheet for the users with JavaScript turned off will be the default stylesheet. When the page loads we do a little check to see if the browser has javascript enabled then we switch to the second stylesheet. 

All this is all in the spirit of _progressive enhancement_.

##__The HTML Code__

The HTML for the navigation is short and easy to understand (nothing fancy). I actually took it from the [fictional website I created](https://ziizium.github.io/aliceandbob/) for the series: [FrontEnd Development: Zero to Hero](https://dev.to/ziizium/frontend-development-zero-to-hero-j0j) with few additions.

```html
<div class="top">
    <header class="header">
        <h1 class="header__name"><a href="index.html">Alice & Bob&trade;</a></h1>
        <span class="hambuger__icon" onclick="openNav()">&#9776;</span>
    </header>

    <nav id="navigation" class="navigation overlay">

        <a href="#" class="closebtn" onclick="closeNav()">&times;</a>

        <ul class="navigation__menu overlay__content">
            <li class="navigation__item">
               <a href="#" class="navigation__link">Web Design</a>
            </li>
            <li class="navigation__item">
               <a href="#" class="navigation__link">Graphics Design</a>
            </li>
            <li class="navigation__item">
               <a href="#" class="navigation__link">Contact Us</a>
            </li>
            <li class="navigation__item">
               <a href="#" class="navigation__link">Our Blog</a>
            </li>
        </ul>
    </nav>
</div>
```

##__The CSS and JavaScript__

Create a new stylesheet and link it with the HTML code above. In the stylesheet paste the snippet below. __To be the best of my understanding the code is easy to understand__ as seen in the [final project for the series on web development](https://dev.to/ziizium/series-final-project-55m0).

The CSS will create the __default view__ for the _navigation_ at different _viewports_ and will be __available to users who have JavaScript turned off in their browser__.

```css
/**
 * Save the code with any name of your choosing
 * preferably nojs.css
 */

* {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
}

a {
    text-decoration: none;
}

li {
   list-style-type: none;	
}

.top {
    background-color: #1f2a47;
    color: #ffffff;
}

.header {
    padding: 1.2em;
}

/**
 * Mobile navigation menu
 */
.navigation__menu {
    margin-top: 1.2em;
    border: 1px solid #cccccc;
}

/**
 * We apply a top borer to the navigation
 * items except the first one.
 */
.navigation__item:not(:first-child) {
    border-top: 1px solid #ccc;
}

/**
 * We turn all links to block level elements
 * then we applie some padding to make them
 * clickable.
 */
.navigation__link {
    display: block;
    padding: 0.8em 1em;
    font-weight: normal;
    color: #ffffff;
}

/**
  * Am pretty sure this is straighforwad :)
  */
.navigation__link:hover,
.navigation__link.active {
    background-color: #06162f;
    color: #ffffff;
}

.header__name {
    margin-bottom: 0.5em;
    font-weight: 700;
    color: #ffffff;
    text-align: center;
}

/**
 * We hide the hamburger icon and the close button
 * because if javascript is disabled in the user's browser
 * they will not be usable.
 */
.hambuger__icon,
.closebtn {
    display: none;
}

/**
 * From 560px (16 * 35em) upwards we turn the
 * the navigation to a grid container and then
 * arrange the navigation links in a grid template
 * area for browsers that support CSS Grid.
 */ 
@media screen and (min-width: 35em) {
	@supports (display: grid) {
		.navigation__menu {
		    display: grid;
		    grid-template-areas: "h1 h2" "h3 h4";
		}

		.navigation__item:nth-child(2) {
		    border-top: none;
		}
	}
}

/**
 * Almost at a desktop view, we turn the navigation
 * into a flex container and we also remove the border
 * from the navigation items.
 */
@media screen and (min-width: 55em) {
	.top {
	    display: flex;
	    justify-content: space-between;
	}

	.navigation__menu {
	    display: flex;
	    border: none;
	    margin-right: 4em;
	}

	.navigation__link {
	    margin-right: 20px;
	}

	.navigation__item:not(:first-child) {
	    border-top: none;
	}
}
```

Save your file and load the HTML in your browser. Snap your browser to a mobile _viewport_, you should get the same output below as seen in Firefox 75:

![A navigation mobile viewport of the navigation](https://dev-to-uploads.s3.amazonaws.com/i/dohlfetlcc3h011xu1q5.png)<figcaption>Mobile viewport</figcaption>

You can resize your browser to see how the navigation adapts to different _viewports_.

When the page loads we need to perform a quick check to see if JavaScript is enabled then we switch to our second stylesheet that will contain code tailored to users that have JavaScript enabled including the _overlay navigation_.

Before writing the JavaScript below create a file named `styles.css` and save it in your _current working directory_.


```js
/**
 * Save this JavaScript in a script tag at the bottom
 * of the HTML file before the closing <body> tag
 * or in another file saved with the .js extension.
 */

if (document.getElementById) {
    // The code in this section will only
    // execute if the user has JavaScript
    // enabled.
    
    // we get the link tag
    let link = document.getElementsByTagName('link');
    
    /**
     * The getElementsByTagName returns an HTMLCollection.
     * The code below assumes you have just one link tag
     * in your HTML file, therefore, we select the first
     * first using its index i.e zero.
     *
     * Link tags also have attributes which inturn contains
     * the href which has a nodeValue that contains the name
     * of the current CSS file.
     *
     * Since JavaScript is enabled for this code to run
     * we switch to the second stylesheet named styles.css
     */
     link[0].attributes.href.nodeValue = "styles.css";
}
```

Save your file and refresh your browser, you should get an HTML with no style applied. This means we've successfully switched to the `styles.css` file. You can confirm this with the browser Developer Tools by performing a simple "Inspect Element" then observe the linked stylesheet in the <code>link</code>.

![Firefox developer tools showing an HTML link tag referencing a file named styles.css](https://dev-to-uploads.s3.amazonaws.com/i/9s4sdkwc0a5zywevcgrr.PNG)<figcaption>The styles.css file in Firefox Developer Tools</figcaption>

Let's change the view a little bit. The following snippet is similar to the code found in the alternate CSS file (the _no javascript_ version created earlier) save it in the `styles.css` file.

```css
/**
  * Save as styles.css
  */

* {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
}

a {
    text-decoration: none;
}

li {
    list-style-type: none;	
}

.top {
    background-color: #1f2a47;
    color: #ffffff;
}

.header {
    padding: 1.2em;
}

.header__name {
    margin-bottom: 0.5em;
    font-weight: 700;
    color: #ffffff;
    text-align: center;
}

.header__name a {
    color: #ffffff;
}
```

Refresh your browser to see the changes (_nothing much for now_).

As I mentioned earlier the _overlay navigation_ will be __available for the mobile _viewport_ only__. So we'll have to use a _media query_ to specify the _viewport_ size that will use the _overlay navigation_.

Since we are not targeting desktop _viewport_ it's best if we specify a _maximum width_ of the _viewport_ in the _media query_ and any _viewport_ size between _zero_ and this _maximum width_ will get our styles for the _overlay navigation_.

```css
@media screen and (max-width: 40em) {
    /**
      * All code for our overlay navigation will live
      * inside this media query.
      */
}
```

To follow along, kindly snap your browser to a _mobile view_ or switch on Responsive Design mode in your browser (<b>`Ctrl`</b> + <b>`Shift`</b> + <b>`M`</b> in Firefox for Windows).

The first thing we'll do is to align the _header name_ and the _hambuger icon_ side-by-side with space between them. We'll achieve this with Flexbox. We'll set the `display` property to `flex` and to get the space between the _header name_ and _hambuger icon_ we use the `justify-content` property with a value of `space-between`.

```css
@media screen and (max-width: 40em) {

    .header {
        display: flex;
        justify-content: space-between; /* for the space between the elements */
    }

}
```

When you take a look at the result in your browser you'll notice changes but there is a tiny problem. The _hambuger icon_ is small. All we have to do is increase its _font size_, while at it we can also add a `cursor` property with a value of `pointer` for _mouse_ users.


```css
@media screen and (max-width: 40em) {

    /* All previous code remain the same */
    
    .hambuger__icon {
        font-size: 30px;
        cursor: pointer;
    }

}
```

Save and refresh your browser. The _hambuger icon_ should look _bigger_. But the _navigation menu_ meant for the _overlay navigation_ is still visible.

![Navigation menu meant for the overlay is still visible](https://dev-to-uploads.s3.amazonaws.com/i/rjog8p4unv5u9ig7lrty.PNG)<figcaption>Navigation is still visible</figcaption>

It's time we apply the _overlay_. The _overlay_ navigation is hidden by default. Based on how we want it we can make it _slide_ from _top_ to the _bottom_ of the screen or from _left_ to _right_. We'll stick with the latter (_left_ to _right_).

The _overlay navigation_ will cover the entire screen hence its _height_ is set `100%`. Its position will be fixed so that we can position it off-screen using _offset_ properties like _top_ and _left_. And since it's an _overlay_ it will appear over the entire page content and we can only achieve this by changing the _stacking context_ of the page using [CSS z-index](https://dev.to/ziizium/css-z-index-j86)

We'll also add aesthetics to indicate that it's over the page using a background color that'll be transparent so that we'll see the page content underneath. We'll resolve to `rgba()` color format and apply an _alpha transparency_ less than _one_. To create the _sliding_ effect we'll resolve to [CSS transition](https://dev.to/ziizium/css-animations-and-transitions-51j8) using the `transition` property with our chosen value.

Since the navigation is sliding from _left_ to _right_ there is a tendency for _overflow_ along the _x-axis_ so it's better we hide the overflow using the `overflow-x` property with a value of hidden.

The snippet below is the resulting code for the explanation in the last three paragraphs.

```css
@media screen and (max-width: 40em) {

    /* All previous code remain the same */
    
    .overlay {
        position: fixed;
        top: 0;
        left: 0;
        width: 0;
        height: 100%;
        z-index: 1;
        background-color: rgba(0,0,0,0.9);
        overflow-x: hidden;
        transition: 0.5s;
    }

}
```

Save your files. The navigation should be out of sight but when you click the _hambuger icon_ to reveal it nothing happens. Why? That's because we've not written the JavaScript that will make it work. Let's fix that.

Switch back to your JavaScript code. From our HTML the _navigation_ has an HTML ID attribute named `navigation`.

We also have a `span` element inside the `header` that contains the _hambuger icon_ and it has an `onclick` event set to a function named `openNav()`.

There is also `a` tag in the _navigation_ with an `onclick` event set to a function named `closeNav()`.

We'll grab the _navigation_ using its ID, and we'll have to create the `openNav` and the `closeNav` function.

```js
// grab the navigation by  its ID
let navigation = document.getElementById('navigation');

/**
 * The openNav function will set the width
 * of the navigation to 100 therefore, it will
 * show on screen.
 */
function openNav() {
    navigation.style.width = "100%";
}

/**
 * The closeNav function will set the width
 * of the navigation to an empty value therefore, it will
 * close up.
 */
function closeNav() {
    navigation.style.width = "";
}
```

Save your files. Now refresh your browser and click the _hambuger icon_ the overlay menu should slide into view but you might find it difficult to close it because we have not styled the close button.

![The incomplete overlay navigation as seen in Firefox Responsive Design Mode](https://dev-to-uploads.s3.amazonaws.com/i/mh71mix4besg47l0pawc.PNG)<figcaption>Incomplete overlay navigation</figcaption>

The close button will be _absolutely_ positioned in the top right corner of the _overlay_ this is possible because of its parent element &mdash; the `overlay` having a position of `fixed`. If you would like to understand this in-depth you can [read my post on CSS positioning](https://dev.to/ziizium/css-positioning-34d8) or [Ahmad Shadeed tutorial on CSS positioning](https://ishadeed.com/article/learn-css-positioning/).

```css

@media screen and (max-width: 40em) {

    /* All previous code remain the same */

    .overlay .closebtn {
        position: absolute;
        top: 20px;
        right: 45px;
        font-size: 3.75em;
    }

}
```

Save your files and refresh to see the changes. You should be able to _open_ and _close_ the _overlay_ navigation but the navigation links still remain un-styled.

When styling the links we have to make them clickable on mobile by setting the links `display` property to `block` and then we add some padding.


```css
@media screen and (max-width: 40em) {

    /* All previous code remain the same */
    
    .overlay a {
        display: block;
        font-size: 2.3em;
        padding: 8px;
        color: #818181;
        text-decoration: none;
        transition: 0.3s;
    }
    
    .overlay a:hover,
    .overlay a:focus {
        color: #f1f1f1;
    }

}
```

Save your file and observe the changes.

![Overlay navigation as seen in Firefox Responsive design mode](https://dev-to-uploads.s3.amazonaws.com/i/gtqdcw0t1e08zf9w73hb.PNG)<figcaption>Overlay navigation</figcaption>

The navigation is almost done, we just need to adjust the position of the _navigation menu_ by moving it to the center of the _overlay_.


```css
@media screen and (max-width: 40em) {
    
    /* All previous code remain the same */
    
    .overlay__content {
        position: relative;
        top: 25%;
        width: 100%;
        margin-top: 30px;
        text-align: center;
    }

}
```

Save your files and try the navigation.

![The completed overlay navigation as seen in Firefox 75 Responsive design mode](https://dev-to-uploads.s3.amazonaws.com/i/7khmkrrtcfrdrq3efofq.PNG)<figcaption>The completed overlay navigation</figcaption>

To finish up we'll apply styles for two breakpoints. The first will set of styles that __will take effect immediately__ after the `40em` breakpoint of the navigation. After this breakpoint, we arrange the navigation in a Grid container and we hide the _hambuger icon_ and _close button_.

At a desktop view, we rearrange the navigation using Flexbox. This is similar to the behavior seen in the CSS file available to users without JavaScript enabled.

```css
@media screen and (min-width: 40.01em) {

	.closebtn,
	.hambuger__icon {
        display: none;
	}
	
	.navigation__link {
        display: block;
        padding: 0.8em 1em;
        font-weight: normal;
        color: #ffffff;
	}

	.navigation__item:not(:first-child) {
         border-top: 1px solid #ccc;
	}

	.navigation__link:hover {
        background-color: #06162f;
        color: #ffffff;
	}

	.navigation__menu {
         margin-top: 1.2em;
         border: 1px solid #cccccc;
	}

	@supports (display: grid) {
		.navigation__menu {
            display: grid;
            grid-template-areas: "h1 h2" "h3 h4";
		}
		.navigation__item:nth-child(2) {
            border-top: none;
		}
	}

}

@media screen and (min-width: 55em) {
	.top {
        display: flex;
        justify-content: space-between;
	}

	.navigation__menu {
        display: flex;
        border: none;
        margin-right: 4em;
	}

	.navigation__link {
        margin-right: 20px;
	}

	.navigation__item:not(:first-child) {
        border-top: none;
	}
}
```

Save your file and perform the following steps:

* Refresh your browser
* Open the _overlay_ navigation and __leave it opened__
* Disable the Responsive Design mode or snap your browser _viewport_ to a desktop view

What do you observe? There are problems with the navigation layout. One is evident (as seen in the image below), the other is not.

![The navigation crashed as seen in Firefox 75](https://dev-to-uploads.s3.amazonaws.com/i/iififhwsi8ugzdj4g12c.png)<figcaption>A crashed navigation</figcaption>

A quick investigation in the Developer tools reveals that while the _overlay_ was opened there was an _inline_ style applied via the `openNav` function and __while we did not close the navigation the inline style was still active when the browser _viewport_ was resized__. This resulted in the weird layout of the navigation.

![Firefox developer tools showing an element with a width of 100](https://dev-to-uploads.s3.amazonaws.com/i/l15fpw829j2pnrvxuwdf.PNG)<figcaption>The cause of weird behavior</figcaption>

You might not notice this if I did not mention it. The fix is simple.

We have to take this situation into consideration and observe when the user resizes the browser without closing the navigation. If this happens we remove the inline style applied by the `openNav` function.

```js
// we get the user current viewport size
let clientWidth = document.documentElement.clientWidth;

/**
 * We add an event listener and observe the "resize"
 * behavior and if the client width is more than the
 * width of that enables the overlay navigation we remove
 * the inline style applied by the openNav function.
 */
window.addEventListener('resize', function() {
    if (clientWidth > 640) {
        navigation.style.width = "";
    }
});
```

The second problem with the layout is when you reduce the _height_ of the _viewport_, the font size of _navigation link_ will cause the browser to add scroll bars in the _overlay navigation_.

The fix is to use a _media query_ and check for the _height_ of the _viewport_ and change the _font size_ accordingly.

```css
@media screen and (max-height: 28em) {
    .overlay a {
	  font-size: 1.25em;
    }
    
    .overlay .closebtn {
	  font-size: 2.5em;
	  top: 15px;
	  right: 35px;
    }
}
```
That's it. The code works but it can be improved. This was an experiment and __there is an issue__ with the _navigation_ that you should be aware of.

If you are on a desktop device perform the following steps:

* Resize your browser window to mobile view to enable the _overlay navigation_
* Now gently resize the browser _height_ you'll realize the _overlay navigation_ closes

I am going to figure out how to fix this, and if you know the fix, let me know in the comments section.

The Github repo:

{% github ziizium/my-webdev-notes %}

_Have fun!_