Before jumping into the code, it’s useful to consider the design of the header menu that you want to build. These can come in many flavours, but one standard layout would be a header with a branding logo on the left and a series of category headings distributed across the rest of the available space. These category headings could be simple links (like this website) or could trigger a submenu to be shown on click/hover (like https://www.trekbikes.com/ for example). On mobile, the web standard is a hamburger icon that toggles an overlay when touched.
Other considerations include maintainability and flexibility. Ideally, the menu should be built in such a way that additional navigation items can be added and removed without breaking the layout, and the design should be able to handle categories and links with both short and long names. It should also be coded such that future adjustments are easy (eg if the color scheme, spacing, size, or branding icon need to change).
Finally, it’s good practice to avoid creating any jarring/abrupt transitions. Specifically, the submenus should appear to fade in or move in, a hamburger icon should provide the user feedback when touched, and any kind of unsightly jank should be eliminated.
A full header menu is a somewhat complex undertaking, and replacing plain CSS with SCSS is useful in the case. To support this, I’ve elected to create a basic Gulp build process that will translate SCSS to CSS, and also provide hot reloading, autoprefixing, and sourcemaps. In addition to other features, SCSS supports the use of variables in CSS, which is helpful for defining reusable breakpoints, heights, and colors.
With SCSS compiling, we can insert some HTML scaffolding into an index.html file and get to work. I like to use this structure as a starting point:
Managing spacing on the web is always important, and there are two important spacing problems to solve with fixed position nav menus:
- The site’s content will fall behind the header –
position: fixedaffects page layout in the same way as
position: absolute, which means that the other elements on the page will no longer respect the space occupied by the header and position themselves as if it was not there. Practically speaking, this means that the top of the
.site-contentelement will fall behind the header. One way to compensate for this is to add padding to
.site-contentsuch that it offsets the height of the header perfectly (which is why setting a defined height on the header is helpful).
- The spacing below the header and above the footer should be consistent for all pages – At this point the header is no longer blocking the content, but it’s not giving it any breathing room either. Although this could be solved by simply adding padding beyond the height of the header, I prefer to set a margin on the child element of the our content (
.content-area, in this case). This decouples offsetting the headers height and giving it appropriate spacing, and also looks much nicer when viewed from Chrome’s dev tools (my dev tools of choice).
Adding animations to navigation toggling makes things feel more natural and contributes to the overall user experience. In this demo all animations are exclusively transitions on the
transform properties, which makes sense for the following reasons:
- Since the height of the dropdown should be determined by the links inside it, it cannot be easily transitioned (ie transitioning
height: auto;does not work).
- Instead of animating height directly, an alternative approach is to animate
max-height. To make this work, the
max-heightis originally set to 0, and then set to a large value (A height which will always be greater than the actual height of the dropdown) when active. This does the trick, but results in a delay when the dropdown is toggled to inactive (as the
max-heightstarts at a value that is larger than the actual height).
transformtransitions allow the clients GPU to be used, which makes them more performant and smooth.
In the case of mobile use, it’s important to keep some minor details in mind:
- As the site grows and navigation links are added, the height of the menu screen may grow to exceed the height of the viewport. Defining the scroll behavior as overflow ensures that the full navigation remains accessible when this happens.
- Mobile safari has the habit of adding a native option bar to the bottom of the viewport, which often blocks parts of the webpage. Adding extra padding to the menu screen can be done to make sure that the items at the bottom of the screen can be accessed when this occurs.