Written by Hamilton Cline
Last updated on January 14, 2019, 5:40 am

Core Navigation

It's important to start with a basic design. One which others can build upon

Nav

<nav class="nav"> <ul> <li><a href="#">Link 1</a></li> <li><a href="#">Link 2</a></li> <li><a href="#">Link 3</a></li> <li><a href="#">Link 4</a></li> <li><a href="#">Link 5</a></li> </ul> </nav> :root { --main-color: #78a5ff; --main-light-color:#e5edff; } .nav ul { list-style-type:none; margin-top: 0; margin-bottom: 0; padding-left: 0; } .nav a { display:inline-block; padding: 0.2em 0.5em; }

Start with a navigation that sets the basis for the rest. This is a basic html structure for a navigation. Use a nav element, but give it a class we can control. Use an unordered list with a series of list item children. Inside each list item, put an anchor. This structure might seem like it can be improved, but indeed, this structure is perfect for not only semantic html, but also for css control.

Nav-default

<nav class="nav nav-default"> .nav-default a { display: block; padding: 0.2em 0.5em; border:0.1em solid transparent; } .nav-default a:hover { text-decoration:none; background-color:var(--main-light-color); }

What are the things worth learning here? Well the most important thing is that we understand the difference between the li element and an a element. List Items are a block element, and Anchors are an inline element. Block elements fill their parent widths, but inline elements only have a width of their content. If we put an anchor into a list item, the anchor can only be clicked where its text is. But if we change the display of the anchor in our .nav element to block, then it will fill up whatever space it is given.

.text-right { text-align:right; } .text-center { text-align:center; } .text-left { text-align:left; }

Of course, this pattern is best placed inside of a smaller area. Someplace vertical, like a sidebar. Add in some text alignment classes and we've got plenty of variety for use.

Active

Let's add in the concept of an .active element.

<li class="active"><a href="#">Link 2</a></li> .nav-default .active>a { border:0.1em solid var(--main-color); }

This is a nice generic class to use within any list structure where something can be chose. When added to one of the sibling li elements, we can use it to display which of the links is currently chosen. You may or may not have noticed the hovering effect on our links before, but now, when clicking between them, we simulate a page change, or section transition.

Flex Navigation

Flex navigation will bring us from the vertical to the horizontal. Getting our nav to be horizontal can be as easy as implementing some flex classes. Understanding how to create and utilize these can be the difference between complicated thoughts about layout and the simple differences between horizontal and vertical.

Flex-box

<nav class="nav nav-default"> <ul class="flex-parent text-center"> <li class="flex-child active"><a href="#">Link 1</a></li> <li class="flex-child"><a href="#">Link 2</a></li> <li class="flex-child"><a href="#">Link 3</a></li> <li class="flex-child"><a href="#">Link 4</a></li> </ul> </nav> .flex-parent { display:flex; } .flex-child { flex:1 1 auto; }

Flex-box is not something super hard to understand how to use, but it can be complicated to implement in more interesting ways. At its most simple, it works on a parent and its immediate children. Set the parent to display:flex and the children will line up in a horizontal row.

This works just fine, and we'll definitely use these later. But for simplicity's sake, let's make our first navigation sub component.

Nav-flex

<nav class="nav nav-flex"> <ul class="text-center"> <li><a href="#">Link 1</a></li> <li><a href="#">Link 2</a></li> <li class="active"><a href="#">Link 3</a></li> <li><a href="#">Link 4</a></li> </ul> </nav> .nav-flex ul { display:flex; } .nav-flex li { flex:1 1 auto; }

When creating sub components, we still use the core component class. After all, this simply changes a small aspect of the design. We implement the same concepts as the .flex-parent and .flex-child classes into one class .nav-flex, which greatly simplifies having to add .flex-child to all those possible list items. In fact, we'll add our new class to the same selectors for .nav-default.

Nav-pills

<nav class="nav nav-pills"> .nav-pills ul, .nav-inline ul { display:inline-flex; overflow:auto; white-space:nowrap; } .nav-pills a { border-radius:1em; margin:0 0.2em; padding:0.2em 1em; }

Let's make a new sub component. We'll add this selector into a new selector for inline-flex. But we won't add the list items. This will mean our pills will be horizontal, but they won't stretch to fill the space. This gives us links of just the size of the text. Adding a border-radius to them will make them look like little pills lined up in a row, and updating the padding and margin will space them out and plump them up.

Nav-inline

An inline flex element gives us some new interesting possibilities if we combine it with some of our other classes.

.nav-pills.text-left

.nav-inline.text-center

.nav-pills.text-right

By adding white-space:nowrap to our inline elements, we'll make sure that their text keeps in a straight line. By adding overflow:auto we ensure that our content can all be reached, even if it's in a space or a screen that's too small for it.

If we want, we can add .flex-wrap to our flexing parent, and it will give us children that wrap around within the available space.

Other Navigation

Time to try some things that break from our core design. Luckily they can still make use of plenty of previous concepts.

Nav-crumbs

<nav class="nav nav-crumbs"> <ul> <li><a href="#">Home</a></li> <li><a href="#">Section</a></li> <li><span>Sub-section</span></li> </ul> </nav> .nav-crumbs li:not(:first-child)::before { content: '/'; }

This style of navigation is often called a breadcrumb navigation. It's most often used to represent a backward trail of linear navigation. Whenever a user moves forward, this nav shows the way back. Add the .nav-crumbs ul into the inline selector to make it flex. Often times the last element is the current page, and therefore would not be a link. Let's add a .nav span selector into our core anchor selector. This will allow us to add an element into any of our designs that doesn't represent a link.

Nav-tabs

<nav class="nav nav-tabs"> .nav-tabs ul { border-bottom:var(--border-size) solid var(--main-color); align-items:flex-end; } .nav-tabs li { margin:0 0.2em; } .nav-tabs a { position:relative; border-bottom-width:0 !important; border-radius: 0.3em 0.3em 0 0; } .nav-tabs .active>a::after { position: absolute; content: ''; bottom: 0; left: 0; transform: translateY(calc(100% - (var(--border-size) * 0.5))); width: 100%; height: calc(2 * var(--border-size)); background-color: white; }

So... to be perfectly honest, this one is goofy. It does some goofy over-rides and it has some goofy quirks. In order to get the gap in the bottom of the active element, technically we're just drawing over it with a white line. In this case we're using an ::after pseudo element and making it look like a white rectangle. Just position it absolutely and cover up the parent's bottom border. It works, but it's kind of gross.

Nav-material

<nav class="nav nav-material"> .nav-material ul { border-bottom: calc(0.5 * var(--border-size)) solid var(--neutral-color); align-items:flex-end; } .nav-material a { position: relative; border-width:0 !important; padding:0.75em 1em; } .nav-material a::after { position: absolute; content: ''; bottom: -1px; left: 0; width: 100%; height: 0; background-color:var(--main-color); transition: height 0.3s; } .nav-material .active>a::after { height: calc(3 * var(--border-size)); }

Android's Material design gave us a very interesting type of tabbed design. It doesn't look like physical manilla tabs, but it does give us some more interesting transitions than we've attempted so far. It uses the same ::after technique, but keeps everything else a lot simpler.

Complex Combinations

Header Navigation

<header class="header"> <div class="flex-parent flex-center"> <div class="flex-none"><h1>Header</h1></div> <div class="flex-child"></div> <div class="flex-none"> <nav class="nav nav-pills"> <ul> <li class="active"><a href="#">Link 1</a></li> <li><a href="#">Link 2</a></li> <li><a href="#">Link 3</a></li> </ul> </nav> </div> </div> </header> .header { background-color:var(--main-light-color); padding:0.5em 0; } .header h1 { margin: 0; font-size: 1em; font-family: verdana,sans-serif; padding:0.2em 1em; } .header .nav .active>a { border-color:transparent; background-color:rgba(255,255,255,0.5); }

Would you look at that, we didn't have to do many new things at all in our actual nav. Of course, I think it requires an understanding of what is a nav, and what is not a nav. Technically only our list of links is a nav, and so the whole header is not a nav, only a small portion. With a little design on our header, we get something that feels pretty common these days. That last selector is getting to be a bit long. Normally we want to avoid selectors like that, as they're difficult to over-ride later. For right now, we'll leave it be and just realize that this IS us over-riding things at this point, and it's gotten that complex.

We can make varieties of our new header arrangement all day long.

Responsiveness

But none of those are responsive, and they're getting a bit unwieldy. If you're on mobile and reading this, things have already gotten a bit gross. So let's inject a bit of responsiveness into our design.

@media (max-width:500px) { .flex-parent.responsive, .nav.responsive ul { display:initial; } }

Let's add a class called responsive to our tools. This when used in conjunction with a nav or a flex parent, will turn off the display:flex of that element on smaller screens. It turns out this is all we need to do to turn out flexiness off. The list items will simply ignore their flex properties, since they are not inside a parent set to flex.

It's possible we could do this with one class on the header, but that wouldn't give us quite enough flexibility in the future.

Hamburger Menu

Header

<header class="header"> <div class="flex-parent responsive flex-center"> <div class="flex-none flex-parent"> <div class="flex-child"> <h1>Header</h1> </div> <div class="flex-none"><label class="hamburger-label" for="hamburger-menu">≡</label></div> </div> <div class="flex-child"></div> <div class="flex-none"> <input type="checkbox" class="hidden hamburger-menu" id="hamburger-menu"> <nav class="nav nav-pills responsive"> <ul> <li class="active"><a href="#">Link 1</a></li> <li><a href="#">Link 2</a></li> <li><a href="#">Link 3</a></li> </ul> </nav> </div> </div> </header> .hidden { display:none; } .hamburger-label { display:none; padding:0.2em 1em; } @media (max-width:500px) { .hamburger-label { display:inline-block; } .hamburger-menu+nav { display:none; } .hamburger-menu:checked+nav { display:block; } }

Let's take it all the way. Let's use a label and a checkbox. Hide the label normally, and show it when the screen is small enough. Show the nav normally, hide it when the screen is small. When the label is clicked, it will activate the hidden checkbox. When the hidden checkbox is checked, it will activate the nav next to it. This is the checkbox trick. No javascript required.

Recap

So what have we learned, in fact? I don't know that we learned anything. We saw a bunch of examples. We got a good start on some common design patterns. The more complex we get, the less of a tutorial it is, and more of something custom for each design's need. Here are a number of helpful, hopefully simple, examples that can be taken and ran with to create bigger and better things.

Written by Hamilton Cline
Last updated on January 14, 2019, 5:40 am