CSS only responsive navigation Apr 21, 2013
Whilst building a Jquery plugin for responsive navigation I started to play around with a CSS only version, just to see what's possible and what we actually need the javascript for. I would say that this is a perfectly feasible solution for a production website but...it's not plug and play, you have to learn how to use the code and adapt it to your site.
Is CSS only feasible?
The good
Responsive solutions are modern
solutions by default, check out browser support for media queries
and you will see that we don't need to worry about old browsers. This is really
important because the solution I propose relies on the :checked
pseudo-class which is supported in these
same browsers. The animation of the slide out panel that houses the links for
the responsive menu uses transform
and transition
which are more or less supported in the
same browsers. I say more or less because IE9 is the weak link here considering
that it does support media queries and it does support :checked
but it doesn't support transitions. The
majority of your mobile users are probably going to be on webkit but for those
on Windows Phone 7 (and therefore IE9) it might not look so smooth but should be
functional.
The bad
There are a few features that the Jquery plugin will have that just can't work in the CSS only solution, or at least I can't figure out a way to make them work! I won't list all the features of the Jquery plugin I am working on just yet but there are some issues with the CSS only solution that will be resolved with a bit of Javascript:
- There is a delay when you tap on the show/hide checkbox.
- You can't click outside the menu to hide it.
- You have to follow quite a strict HTML structure, placing the checkbox before everything else.
There a few more advantages of the Jquery solution but that will be explained in the next article.
How does it work?
First of all we have a show/hide menu toggle,
which in this case is a checkbox that has been hidden by a font icon placed over
the top using the label:after
pseudo element.
The toggle is hidden by default and only shown on smaller screens. By using the
:checked
pseudo class we can change the icon
that is displayed once the checkbox has been clicked, in this case we are going
to turn it into a "close" icon. For this to work the checkbox
must be placed before the <label>
because we are relying on this
sibling selector to change the icon:
.slide-checkbox:checked ~ .slide-toggle:after {
content: '"';
}
.slide-checkbox
is the checkbox
, .slide-toggle
is the <label>
The cool part is the slide out menu, in fact it's not really the menu that slides out but more the content that slides over to the right, dragging the menu along with it. In the media query the menu is hidden off-canvas using this CSS:
.nav {
width: 70%;
position: absolute;
left: 0;
top: 0;
transform: translateX(70%) scale(1);
}
(This has been shortened for readibility, in the demo you'll see the full code with browser prefixes.)
Now, the important part is sliding the content over. To do this I am relying
on the content to be inside a <div
class="slide">
and to follow the checkbox
in the HTML markup because of this
CSS:
.slide-checkbox:checked ~ .slide {
transform: translateX(70%) scale(1);
}
What this is saying is: "when the .slide-toggle is checked, then any div with a class of "slide" that is adjacent in the markup should be transformed". When we slide the div over we also bring the nav into view.
Another important aspect is that everything, including the checkbox, is
wrapped inside <div
class="outer">
which has overflow: hidden
set and this stops scrollbars
appearing once the content slides over.
Here's a breakdown of the necessary HTML structure:
<body>
<div class="outer">
<input type="checkbox" id="slide-checkbox" class="slide-checkbox" role="button">
<label for="slide-checkbox" class="slide-toggle" onclick></label>
<div class="slide">
<ul class="nav">
<!-- menu content here -->
</ul>
<!-- add any content you want in here -->
</div>
</div>
</body>
Something that is pretty flexible is the .nav
, this can be a <div>
instead of a <ul>
and you don't need to be limited to
just putting a menu in there. Also, the nav can be pretty much anywhere inside
the <div class="slide">
,
even inside other divs.
The best way to see what's going on though is to download the demo and have a look at the CSS because all the important parts are heavily commented. And, if you're interested in the Jquery solution when it comes out, which will have a range of configurable options, then follow on twitter and/or watch the project on github. Please let me know what you think in the comments.
Acknowledgements
Thanks to Marnu
Lombard for creating a really useful pull request that made me change from translate3D to
translateX and put the toggle on the label:after
instead of the checkbox:after
. That really helped browser
compatibility.
Thanks to Ben and Dan "5 mins" Caragea for mobile testing.