<div class="js-offcanvas">
<div class="offcanvas">
<div class="offcanvas__pusher">
INSERT HEADER
<div class="offcanvas__content">
<div class="offcanvas__content-inner">
<button class="offcanvas__close"><svg class="icon icon--close ">
<use xlink:href="#icon--close" />
</svg>
Close</button>
INSERT NAV
</div>
</div>
<button class="offcanvas__opener"><svg class="icon icon--menu ">
<use xlink:href="#icon--menu" />
</svg>
Menu</button>
INSERT MAIN
<div class="offcanvas__overlay"></div>
</div>
</div>
</div>
<div class="js-offcanvas">
<div class="offcanvas">
<div class="offcanvas__pusher">
INSERT HEADER
<div class="offcanvas__content">
<div class="offcanvas__content-inner">
<button class="offcanvas__close">{{> @icon name="close"}} Close</button>
INSERT NAV
</div>
</div>
<button class="offcanvas__opener">{{> @icon name="menu"}}Menu</button>
INSERT MAIN
<div class="offcanvas__overlay"></div>
</div>
</div>
</div>
/* No context defined for this component. */
$offcanvas__width: rem(300);
.offcanvas {
position: relative;
height: 100%;
overflow-x: hidden;
}
.offcanvas__pusher {
height: 100%;
position: relative;
left: 0;
transition: transform 0.3s ease;
transform: translate3d(0, 0, 0);
backface-visibility: hidden;
}
.offcanvas__overlay {
position: absolute;
top: 0;
right: 0;
width: 0;
height: 0;
background: rgba($color__dark, 0.4);
opacity: 0;
z-index: 100;
transition: opacity 0.2s, width 0.1s 0.2s, height 0.1s 0.2s;
}
.offcanvas__content {
position: fixed;
top: 0;
right: 0;
left: auto;
overflow-y: auto;
width: $offcanvas__width;
height: 100%;
z-index: 101;
background-color: $color__brand--one;
color: $body__font-color;
backface-visibility: hidden;
transform: translate3d(100%, 0, 0);
.no-js & {
position: static;
width: 100%;
transform: none;
}
}
.offcanvas__content-inner {
opacity: 0.7;
transition: opacity 300ms 100ms ease, transform 400ms ease;
transform: translate3d(-$offcanvas__width, 0, 0) scale3d(0.8, 0.8, 0.8);
transform-origin: 50% 0%;
.no-js & {
opacity: 1;
transform: none;
}
}
.offcanvas__opener,
.offcanvas__close {
display: inline-block;
background-color: transparent;
border: 0;
outline: 0;
line-height: 1.9;
padding: rem(5) 0;
cursor: pointer;
.icon {
vertical-align: top;
}
}
.offcanvas__opener {
color: $color__bright;
margin-right: rem(10);
&:hover {
color: $color__dark;
}
}
.offcanvas__close {
width: 100%;
padding: rem(11) rem(12);
text-align: left;
&:hover {
color: $color__bright;
}
}
// STATES
.offcanvas--left { // add class to body
.offcanvas__content {
transform: translate3d(-100%, 0, 0);
left: 0;
right: auto;
}
}
.offcanvas--open {
.offcanvas {
overflow: hidden;
}
.offcanvas__pusher {
transform: translate3d(-$offcanvas__width, 0, 0) scale3d(1, 1, 1);
}
&.offcanvas--left {
.offcanvas__pusher {
transform: translate3d($offcanvas__width, 0, 0) scale3d(1, 1, 1);
}
}
.offcanvas__content {
-webkit-overflow-scrolling: touch;
}
.offcanvas__content-inner {
transform: translate3d(0, 0, 0);
opacity: 1;
}
.offcanvas__overlay {
transition: opacity 0.2s;
width: 100%;
height: 100%;
opacity: 1;
}
.offcanvas__opener {
transition: opacity 0.3s ease;
opacity: 0;
pointer-events: none;
}
}
// NO-JS FALLBACK
.no-js {
.offcanvas__opener,
.offcanvas__close {
display: none;
}
}
import Base from '../../_config/base';
class Offcanvas extends Base {
constructor(el) {
super(el);
this.config = {
openClass: 'offcanvas--open',
overlaySelector: '.offcanvas__overlay',
openButtonSelector: '.offcanvas__opener',
closeButtonSelector: '.offcanvas__close',
};
const togglerOpen = this.$el.querySelector(this.config.openButtonSelector);
const togglerClose = this.$el.querySelector(this.config.closeButtonSelector);
const overlay = this.$el.querySelector(this.config.overlaySelector);
togglerOpen.addEventListener('click', this.toggle.bind(this));
togglerClose.addEventListener('click', this.toggle.bind(this));
overlay.addEventListener('click', this.toggle.bind(this));
}
toggle() {
this.$el.classList.toggle(this.config.openClass);
}
}
Offcanvas.className = 'Offcanvas';
export default Offcanvas;
This component is a combination of the <header class="header" />
and all containers & buttons for the off-canvas part.
The DOM of the page should look like this (example is simplified):
<body class="js-offcanvas">
<div class="offcanvas">
<div class="offcanvas__pusher">
<header class="header">
<div class="offcanvas__content">
<button class="offcanvas__close"></button>
<div class="header__nav">
<nav class="main-nav"> main navigation...</nav>
</div>
<div class="header__meta">
meta-nav...
</div>
</div>
<button class="offcanvas__opener"></button>
</header>
<main> Her comes the content...</main>
<footer>footer of page</footer>
<div class="offcanvas__overlay">
</div>
</div>
</body>
The class js-offcanvas
is to initialize the off-canvas functions (toggle with buttons). Toggle Buttons needs the class js-offcanvas__toggler
for the eventhandler.