Building menu’s for responsive websites can be tricky. For small devices, we basically want to hide the menu by default, so that it doesn’t take up a lot of space, and then show it only when the user want’s it. For an overview of solutions for this, check this article on CSS tricks. The problem is that most methods either require javascript, or have weird, hacky, unsemantical HTML, or both. Personally, I never even considered any solution relying on javascript – the idea of some users being completely incapable of accessing something as crucial as the navigation just seems to wrong to me. Some variations of the javascript solutions just leaves the menu expanded for non-javascript users – which is better – but then the menu blocks most of the users screen instead, forcing the user to scroll past it to get to the content. Of course we can do better.
The :target solution
When I first read about the :target solution, I was sold – no javascript required and semantic markup. Perfect. I have been using this method, or variations of it ever since. It’s used on this website (in the format described below). If you aren’t familiar witih this method, go check out this tutorial. It’s basically toggling showing the menu via modyfying the hash part of the url, so leading the user to #nav would show the menu.
A drawback
Unfortunately this method pollutes the browser history — every time the user opens or closes the menu, a new entry is placed in their browser history. This can make it really annoying to try to get back to a previous page, if you have to click through a lot of ‘pages’ where you were just interacting with the menu. Clearly, menu interaction does not belong in the browser history. But that’s very easy to fix, with javascript!
But you said javascript solutions were not okay?
This is where progressive enhancement comes in. While it’s not okay to require javascript in order to provide something as fundamental as a menu, it’s absolutely okay to improve an already functional experience using javascript. In fact, that’s what you should do. Using javascript, we just intercept and block the clicks on our menu triggering anchor links, and instead we toggle some css class for activating the menu.
var $nav = $(".mobile-menu");
$(".mobile-menu-show-button").on("click", function(e){
e.preventDefault() //prevents #nav from registering in browser
$nav.addClass("active"); //shows the menu
});
//add the .active trigger to show the menu
#nav.active .nav-list,
#nav:target .nav-list //what we're STILL using for non-js
{
//show menu...
}
In the end, we get the best of both worlds — a fully functional, semantical, non-javascript dependent mobile menu experience for our non javascript users, and not only that but also a clean browser history for our javascript users.
If you have any questions or comments, please let me know!