Sticky Navlinks

You sell used pianos and are building a website. So far you've got this basic structure with a header, some navlinks, and some placeholder text:

html
css
preview

The list of navlinks is not a typical list, so you strip off the indentation and bullets:

html
css
preview

Then you turn them into a horizontal row using Flexbox and place them on a black background to give a piano-ish color scheme:

html
css
preview

Several things are off here. The links are hard to read and there's too much space between the header and the navlinks. You fix the colors and margins, remove the underlines, and add a hover color:

html
css
preview

Before you do any further work on the website, you conduct a user study, like any professional. You find that a many of your customers found you by searching the internet on their mobile phones. Therefore, you want to make sure your page is usable on small screens. The navlinks need to be a lot bigger in order for imprecise human fingers to land on them. You add some padding to the anchors:

html
css
preview

This is better, but when the window gets small, the navlinks get cut off. You want them to appear in a vertical stack in such situations, but that will take up a lot of space. You've seen other mobile sites make a vertical stack of navlinks appear when the viewer clicks on a little button with a "hamburger" icon, so you add one of those:

html
css
preview

The three lines look like the buns and patty of a hamburger. You only want the hamburger icon to appear on mobile, so you hide it by default and display it using a media query that checks for a small screen:

html
css
preview

Resize the window or zoom in and out until you see the icon appear and disappear. Adjust the media query condition as necessary.

You want the heading and the hamburger icon to appear on the same line, so you switch the header to a horizontal flex layout, and you also hide the nav element for the time being:

html
css
preview

Shrink the window or zoom in until the media query kicks in.

To distinguish the header from the content on small screens, you decide to invert the colors:

html
css
preview

When the viewer clicks on the hamburger icon, you want a vertical stack of navlinks to appear. This requires JavaScript. You haven't read about that yet, but somehow you manage to cobble together this script, which toggles the class open on the nav element:

html
css
js
preview

You add a ruleset to the media query to make a nav element with class open visible, and you position it absolutely:

html
css
js
preview

The nav element appears, but it needs to sit below its parent. Try adjusting its edge properties.

Now you want the links to appear in a vertical stack, but only on small screens. Try changing the layout direction. Once it's vertical, try moving the stack to the right, so it appears just below the hamburger icon.

This is working pretty well:

html
css
js
preview

You have just one last gripe. By the time your customers get to the bottom of the page, the navlinks are very much out of reach and would require a lot of swiping to get back to. You consider the options:

You don't dislike the final option, but you aren't sure how to do it. You think fixed positioning might do the trick:

html
css
js
preview

But you remember that fixed positioning takes the element out of the flow and the subsequent content fills in the vacated space. Some of the text is positioned behind the header. Then you learn of sticky positioning. Recall the positioning behaviors you read about earlier:

An element with sticky positioning appears in its normal static position until it starts to disappear because an ancestor box is being scrolled. When it starts to disappear, it then switches to being anchored against the scrolling ancestor. You switch the header to sticky positioning and anchor it to the top of its scrolling ancestor:

html
css
js
preview

Try scrolling. The header remains visible. The navlinks button still behaves as desired. Whew!

Try adding a drop shadow to the header to give a sense of layering. Try making the header snap to the left, right, and top edges of the viewport. Try adding changing the background color of link that's currently being clicked using the :active pseudoselector.