Works with CSS only - jQuery plugin available too!
This project is an attempt to create a navigation system that provides basic functionality even without javascript, with CSS only. This gives us a decent fallback if our jQuery plugin is not available for some reason.
The first goal was to see how far we could go with CSS alone. Every site should be usable without javascript (and also without CSS for that matter). We tried to make it as "advanced" as we possibly could, but we are however limited by the CSS selectors. Drop down effects with CSS provide basic functionality, but it's not ideal.
Our jQuery plugin adds some sugar to the navigation, making it more user friendly and a bit more awesome... :)
With our jQuery plugin you can traverse the sub menu's by touch or clicking and optionally by moving your mouse over it. If you're a keyboard fan, then you can spam your tab
key to the menu and hit enter
to open or close a sub menu (or open a link of course).
- IE 8 (needs extra effort)
- IE 9 and above
- Firefox
- Chrome
- Android 4.3 and above
- ...
This class will let CSS handle the :hover
effects for opening and closing the menu. If our jQuery plugin is loaded, it will remove this class and take over for some nicer effects!
<!DOCTYPE html>
<html lang="en" class="nav-no-js">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
It is highly recommended that you include normalize.css!
Include some defaults in your CSS (or use our defaults.css
). This will allow mobiles to load the correct media queries on your website and fix box-sizing issues with padding and borders. The html
font-size is the "root" font-size. Any rem
unit will always be relative to this. With 62.5%, 1.6rem
= 16px
. Our CSS uses rem
units, so you'll need this!
@viewport { width: device-width; }
@-ms-viewport { width: device-width; }
* {
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
html {
font-size: 62.5%;
}
body {
font-size: 1.4rem;
line-height: 2.4rem;
}
Because we use REM units in CSS, you should include the REM unit polyfill for some older browsers. Or you can edit the CSS and use another unit.
Because IE 8 doesn't support HTML5, you should include html5shiv.
IE 8 doesn't support media queries, so you should also inlude our ie8.css
after the normal stylesheet. (it contains all "desktop" styles without media queries. IE 8 won't jump to the mobile menu on resize.
Ideally you would concatenate all CSS files into one file, but for clarity I'll add them separately. You could easily replace/modify the *-layout.css
files with your custom styles.
<link rel="stylesheet" href="css/normalize.min.css">
<link rel="stylesheet" href="css/defaults.min.css">
<link rel="stylesheet" href="css/nav-core.min.css">
<link rel="stylesheet" href="css/nav-layout.min.css">
<!--[if lt IE 9]>
<link rel="stylesheet" href="css/ie8-core.min.css">
<link rel="stylesheet" href="css/ie8-layout.min.css">
<script src="js/html5shiv.min.js"></script>
<![endif]-->
<script src="js/rem.min.js"></script>
In the
public/css
folder, you will find*-core.css
,*-layout.css
and*-full.css
files. The latter combines the first two, so you can choose what files you want to use. A minified version is also included. The original SASS files are in theassets/sass
folder.
To enable our jQuery plugin, you will need to include jQuery and our plugin script and then run .nav()
on your <nav>
. Too increase page loading speed you might want to add this right before your closing </body>
tag.
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.2/jquery.min.js"></script>
<script src="js/nav.jquery.min.js"></script>
<script>
$('.nav').nav();
</script>
You can set some options when calling .nav()
:
$('.nav').nav({
// Mobile menu button selector
navButton: '.nav-button',
// Sub menu selector (<li>)
subMenu: '.nav-submenu',
// Open sub menu's on mouse over
// when not in mobile mode
mouseOver: true,
// When clicking/touching a sub menu link, it will open the sub menu...
// Not disabling the links will make sub menu's unreachable on touch devices!
// A link with [href="#"] will always be disabled, regardless of this setting.
// Disable the actual link in a particular mode:
// always|never|mobile|desktop
disableSubMenuLink: 'always',
// How fast should a sub menu open/close? (ms)
slideSpeed: 500
});
For CSS-only functionality, it is important to place .nav-button
link right before <nav>
and .nav-close
right after <nav>
. These need to be links, because that works better for mobile touch. The links can be positioned anywhere using absolute
positioning. The .nav-close
button will only show up if our jQuery plugin is not available.
The <nav>
tag should also have a .nav
class, as there might be other nav areas that shouldn't be styled.
<a href="#" class="nav-button">Menu</a>
<nav class="nav">
<ul>
<li><a href="/link/to/page">Link</a></li>
</ul>
</nav>
<a href="#" class="nav-close">Close Menu</a>
IMPORTANT: We experienced issues where some smartphones (Samsung S4) "think" we want to touch links rather than a
<span>
etc. Because of this, every "touchable" item (including sub menu's) should be an<a>
tag withhref
attribute.
TIP: You could create an extra
.nav-button
anywhere in the DOM that would only be shown if our jQuery plugin is loaded. The original one can then be hidden. Just add your own classes and write the CSS to show/hide when appropriate.
Each "link" should be wrapped in an <a>
tag. If you don't want an actual link (sub menu), just write a #
in the href
attribute. It is recommended to use a #
for sub menu's to allow for touch navigation! Dont forget to add the .nav-submenu
class to the <li>
containing the sub menu.
<nav class="nav">
<ul>
<li><a href="/link/to/page">Link</a></li>
<li class="nav-submenu"><a href="#">Sub Menu</a>
<ul>
<li><a href="/link/to/sub/page">Link</a></li>
</ul>
</li>
</ul>
</nav>
There was one more issue when not using javascript on mobiles (at least on the Samsung S4). If you would open a sub menu in the top level and then touch the next sub menu in the top level, that sub menu would open and the previous one would close. (Duh!)
Unfortunately, there is some kind of delay. When the previous menu closes, the one you touched moves upwards. However, the phone seems to remember the touch position on the screen and actually activates the link that ends up under your finger.
So we decided not to collapse the sub menu's on mobiles if you don't use our jQuery plugin.
The navigation is tested when placed in the body
, but you should be able to wrap other div's around it if needed. As long as you don't experience issues with the fixed
placement of <nav>
on mobiles.
The <header>
used in the example is not needed for the navigation to work. But most sites will probably have some sort of header, so I just included it to show how it can blend in with the navigation.
The SCSS files are split to make editting them a bit easier:
_config.scss
: Some vars for colors, line-heights etc._core-*.scss
: Essential CSS to make the navigation work_layout-*.scss
: Change colors, paddings etc. in these files
The included web font is generated by a Gulp plugin with the included Gulpfile, and contains the .svg
icons in assets/icon-font
. You can also use another icon font. Just remove the references in the nav-*.scss
files and edit/remove the icon styles in the _layout-*.scss
files.
Example icons downloaded from Flaticon.
Regretably there is no CSS way to enable navigating through the drop down menu's with the tab
key. The tab
key triggers the :focus
selector on the links, but not :hover
on the parent <li>
. So there is no way to keep the parent menu's open when tabbing into a sub menu... This does work when you use our jQuery plugin.
- Android 4.3 browser and lower
This issue is only relevant when using no javascript. (CSS navigation only)
Android 4.3 browser and lower have issues when combining pseudo classes with adjacent or general sibling selectors. Therefor the "close menu" button is not shown when you press the menu button. It does show when you use the menu.
- Android 4.3
When you zoom in, the header scales to fit in the browser window, but when you zoom out again, it doesn't seem to "resize" to full width immediately.