Accessible Off-canvas Push Menu with jQuery and CSS3
| File Size: | 4.05 KB |
|---|---|
| Views Total: | 3322 |
| Last Update: | |
| Publish Date: | |
| Official Website: | Go to website |
| License: | MIT |
Just another jQuery & CSS3 based off-canvas navigation (push menu) that uses JavaScript to dynamically adds WAI-ARIA roles to make your site navigation more accessible.
How to use it:
1. Create a off-canvas navigation with a toggle button and wrap them together with the main content into a wrapper like this:
<div class="site-wrapper">
<div class="main">
<div class="wrap">
<!-- Hamburger menu toggler -->
<a href="#navigation" title="navigation menu" aria-label="navigation menu">
Navigation Menu
<span class="bar bar-1"></span>
<span class="bar bar-2"></span>
<span class="bar bar-3"></span>
</a>
<!-- Main content -->
...
</div>
</div>
<!-- Off-canvas navigation -->
<nav id="navigation" role="navigation">
<ul>
<li class="active"><a href="#">Home</a></li>
<li><a href="#">Works</a></li>
<li><a href="#">Contact</a></li>
<li><a href="#">About</a></li>
<li><a href="#">Blog</a></li>
</ul>
</nav>
</div>
2. The basic CSS styles.
body { overflow-x: hidden; }
*:focus { outline: 1px solid #03A9F4; }
.main {
position: relative;
padding: 0 20px;
margin-left: 0;
-webkit-transition: all 0.3s cubic-bezier(1, 0.1, 0, 0.9);
transition: all 0.3s cubic-bezier(1, 0.1, 0, 0.9);
-webkit-transform: translateZ(0) translateX(0);
transform: translateZ(0) translateX(0);
}
.main > .wrap {
padding: 80px 0;
max-width: 1200px;
margin: 0 auto;
}
[data-nav-visible="true"] .main {
-webkit-transform: translateZ(0) translateX(300px);
transform: translateZ(0) translateX(300px);
}
3. Style the hamburger toggle button.
a[href="#navigation"] {
display: inline-block;
position: absolute;
top: 20px;
left: 20px;
text-indent: -9999px;
background: #03A9F4;
height: 60px;
width: 60px;
border-radius: 100%;
box-shadow: 0px 0px 5px 0px rgba(0, 0, 0, 0.5);
-webkit-transition: all 0.3s cubic-bezier(1, 0.1, 0, 0.9);
transition: all 0.3s cubic-bezier(1, 0.1, 0, 0.9);
-webkit-transform: translateZ(0) scale(1);
transform: translateZ(0) scale(1);
}
a[href="#navigation"]:hover { opacity: 0.9; }
[data-nav-visible="true"] a[href="#navigation"]:before {
-webkit-transform: translateZ(0) scale(1);
transform: translateZ(0) scale(1);
}
[data-nav-visible="true"] a[href="#navigation"] .bar { margin-top: -3px !important; }
[data-nav-visible="true"] a[href="#navigation"] .bar.bar-1 {
-webkit-transform: translateZ(0) rotate(45deg) translateY(0);
transform: translateZ(0) rotate(45deg) translateY(0);
}
[data-nav-visible="true"] a[href="#navigation"] .bar.bar-2 { opacity: 0; }
[data-nav-visible="true"] a[href="#navigation"] .bar.bar-3 {
-webkit-transform: translateZ(0) rotate(-45deg) translateY(0);
transform: translateZ(0) rotate(-45deg) translateY(0);
}
a[href="#navigation"]:before {
content: '';
position: absolute;
display: block;
height: 100%;
width: 100%;
border-radius: 100%;
-webkit-transform: translateZ(0) scale(0);
transform: translateZ(0) scale(0);
background: #FF5722;
-webkit-transition: all 1s cubic-bezier(1, -0.25, 0, 1.25);
transition: all 1s cubic-bezier(1, -0.25, 0, 1.25);
}
a[href="#navigation"] .bar {
display: block;
position: absolute;
background: white;
height: 4px;
width: 26px;
top: 50%;
left: 50%;
margin-left: -13px;
margin-top: -2px;
border-radius: 2px;
opacity: 1;
-webkit-transform: translateZ(0) rotate(0deg);
transform: translateZ(0) rotate(0deg);
-webkit-transition: all 0.7s cubic-bezier(1, 0.1, 0, 0.9);
transition: all 0.7s cubic-bezier(1, 0.1, 0, 0.9);
}
a[href="#navigation"] .bar.bar-1 {
-webkit-transform: translateZ(0) rotate(0deg) translateY(-8px);
transform: translateZ(0) rotate(0deg) translateY(-8px);
}
a[href="#navigation"] .bar.bar-3 {
-webkit-transform: translateZ(0) rotate(0deg) translateY(8px);
transform: translateZ(0) rotate(0deg) translateY(8px);
}
4. Style the off-canvas navigation.
nav[role="navigation"] {
position: fixed;
top: 0;
left: 0;
bottom: 0;
padding: 0;
overflow: hidden;
background: #111;
width: 300px;
box-sizing: border-box;
-webkit-transition: all 0.3s cubic-bezier(1, 0.1, 0, 0.9);
transition: all 0.3s cubic-bezier(1, 0.1, 0, 0.9);
-webkit-transform: translateZ(0) translateX(-100%);
transform: translateZ(0) translateX(-100%);
}
[data-nav-visible="true"] nav[role="navigation"] {
-webkit-transform: translateZ(0) translateX(0);
transform: translateZ(0) translateX(0);
}
nav[role="navigation"] > ul {
margin: 0;
padding: 40px 0;
list-style: none;
-webkit-transition: all 0.2s ease 0.3s;
transition: all 0.2s ease 0.3s;
-webkit-transform: translateZ(0) translateX(100%) scale(0.6);
transform: translateZ(0) translateX(100%) scale(0.6);
}
[data-nav-visible="true"] nav[role="navigation"] > ul {
-webkit-transition: all 0.2s ease 0.1s;
transition: all 0.2s ease 0.1s;
-webkit-transform: translateZ(0) translateX(0) scale(1);
transform: translateZ(0) translateX(0) scale(1);
}
nav[role="navigation"] > ul li.active a {
border-left: 2px solid #03A9F4;
background: #222;
}
nav[role="navigation"] > ul a {
display: block;
padding: 15px 20px;
color: white;
font-size: 18px;
text-decoration: none;
border-left: 2px solid transparent;
}
nav[role="navigation"] > ul a:hover { background: #03A9F4; }
5. Include the latest version of jQuery library from a CDN.
<script src="//code.jquery.com/jquery-2.1.4.min.js"></script>
6. The core JavaScript to enable the accessible off-canvas menu.
var Nav = function($) {
return {
init: function() {
this.cacheDom();
this.setupAria();
this.bindEvents();
},
cacheDom: function() {
this.$site = $('.site-wrapper');
this.$navBtn = this.$site.find('[href="#navigation"]');
this.$navBtnExpanded = this.$site.find('[aria-expanded]');
this.$nav = $('#navigation');
this.$navFirstLink = this.$nav.find('li:first-child a');
this.$navLastLink = this.$nav.find('li:last-child a');
this.$content = this.$site.find('.content');
},
bindEvents: function() {
this.$navBtn.on('click', this.toggleMenu.bind(this));
this.$navBtnExpanded.on('keydown', this.setFocus.bind(this));
this.$navFirstLink.on('keydown', this.returnFocusFirst.bind(this));
this.$navLastLink.on('keydown', this.returnFocusLast.bind(this));
},
setupAria: function() {
this.$navBtn.attr({
'role': 'button',
'aria-controls': 'navigation',
'aria-expanded': 'false'
});
this.$site.attr({
'data-nav-visible': 'false'
});
},
toggleMenu: function() {
var self = $(event.currentTarget);
event.preventDefault();
self.attr('aria-expanded') === 'true' ? this.closeMenu() : this.openMenu();
},
openMenu: function() {
this.$site.attr({
'data-nav-visible': 'true'
});
this.$navBtn.attr({
'aria-expanded': 'true'
});
},
closeMenu: function() {
this.$site.attr({
'data-nav-visible': 'false'
});
this.$navBtn.attr({
'aria-expanded': 'false'
});
},
returnFocusFirst: function() {
if (event.keyCode === 9) {
if (event.shiftKey) {
event.preventDefault();
this.$navBtn.focus();
}
}
},
returnFocusLast: function() {
if (event.keyCode === 9) {
if (!event.shiftKey) {
event.preventDefault();
this.$navBtn.focus();
}
}
},
setFocus: function() {
var self = $(event.target);
if (event.keyCode === 9) {
if (self.attr('aria-expanded') == 'true') {
if (!event.shiftKey) {
event.preventDefault();
this.$navFirstLink.focus();
} else {
if (event.shiftKey) {
event.preventDefault();
this.$content.focus();
}
}
}
}
}
}
}(jQuery);
Nav.init();
This awesome jQuery plugin is developed by dapacreative. For more Advanced Usages, please check the demo page or visit the official website.











