100% Pure HTML/CSS Page Navigation - No JavaScript Required
Tags: css, html, navigation, tips
Published: 2018-10-13 08:15:07

# Build a page navigation system using only HTML and CSS

This is a little trick I've acquired over the years, and for most use cases it works wonders in keeping my code clean, lean and free from unnecessary JavaScript. 

Imagine a Single Page Application or a page showing and hiding panels, modals etc. without reloading the page. Clicking on one of these triggers will alter the content of the page. 

Traditionally this was done using jQuery or some home made JavaScript functions altering the styles or classes on the elements in question. Setting a class with `display: none;` to hide or `display: block;` to show them are classics, along with setting that style directly on the elements.

_Well, there is no need to do it so complicated at all._

## Examples

Take a look at this HTML:

```html
...
<!-- Just a typical nav-element with a list of links -->
<nav>
    <a href="#page1">Page 1</a>
    <a href="#page2">Page 2</a>
    ...
    <a href="#page5">Page 5</a>
</nav>
...
<!-- 
    All the divs with the content you want to serve. Notice page1 sits last. 
    This is important for the CSS to work.
-->
<div id="page2" class="page">[some content]</div>
<div id="page3" class="page">[some content]</div>
...
<div id="page5" class="page">[some content]</div>
<div id="page1" class="page default">[some content]</div>
...
```

Here we have the `nav` element with it's links, and the `div`s with their content. Notice the ID of the DIV is the same as the anchor link. One important thing is placing the first page, or rather the div with the content you want to be shown when no link is clicked yet, last.

And here is the important parts of the CSS:
```css
/* This hides all pages */
.page {
    display: none;
}

/* This displays the first page */
.default {
    display: block;
}

/* This displays the page corresponding to the one you clicked on */
:target {
    display: block;
}

/* This hides the default page when another page is clicked */
:target ~ .default {
    display: none;
}
```

Or condensed:
```css
.page, :target ~ .default {
    display: none;
}

.default, :target {
    display: block;
}
```
## Demo

Now, the CodePen I've embedded below contains CSS and HTML not displayed in this example, but that's just to make it "pretty" and has nothing to do with the actual function of the nav. Just the layout. Try it out before we unveil the secret sauce, and a caveat.

{% codepen https://codepen.io/canis1980/pen/WaEXZz/ %}

## Unveiling the secret

The first part of this secret is the links. The `href` contains only hashed identifiers  like the ones you use to jump up and down a page. The hash in a URL gets picked up by CSS using the `:target` pseudo-selector, allowing us to use that to change the style of the element who's ID is equal to the hash in the URL.

The second part is how we use the selectors to hide the default page. Since we are placing that last, we can use the sibling selector to target all elements with the class `.default` that comes after the element who is targeted. 

Now the caveat is that unless the page is structured or laid out in such a way that the top of the "pages" are also at the top of the browser, the page might jump. Some CSS/HTML only hacks can be done by using container DIVs that holds the ID and are positioned with `top: 0px;` and contains the actual content DIV pushed down with margins, or some other similar approach. 

Hope you enjoyed!

Oh, and if you have other approaches to do SPA and similar type navigation without JavaScript, please share in the comments.