[![Build Status][ci-img]][ci] [ci-img]: https://travis-ci.org/toomuchdesign/offside.svg [ci]: https://travis-ci.org/toomuchdesign/offside
Offside.js is a minimal JavaScript kit without library dependencies to push things off-canvas using just class manipulation. It's goal is to provide a super-lightweigth, efficient and customizable way of handling off-canvas menus/elements on modern website and web applications.
Offside.js comes with its own default stylesheet which make use of CSS 3D transform, but you can write your own CSS hooking your style with Offside classes. This ensures super flexibility and completely decouples Offside.js from your style/markup.
Offside.js is a fast growing kid, please feel free to drop me a line if you use it in a project of yours!
- Single element
- Single element (without css 3dtransforms)
- Multiple elements
- Multiple elements (without css 3dtransforms)
- Typical setting
- Minimal DOM manipulations
- No library dependencies
- Uses CSS3 3D transforms (if you want to)
- No injected style. Offside entirely relies on classes manipulations
- BEM-like style
- Requirable through require('offside-js')
- Degrades gracefully on browsers not supporting CSS3 3D transforms
- Handles multiple off-canvas elements
- Left/right off-canvas
- Style agnostic
- No need of extra classes or any specific markup.
All modern browsers and ie9+.
Offside.js relies on EventTarget.addEventListener / removeEventListener and querySelector / querySelectorAll methods without any fallback.
Check relative browser compatibility:
You can install Offside.js as a Bower or NPM dependency.
# Bower
bower install offside --save
# NPM
npm install offside-js --save
<!-- Put these into the <head> -->
<link rel="stylesheet" href="dist/offside.css">
<script src="dist/offside.js"></script>
<!-- Off-canvas toggle button -->
<button type="button" id="my-button">Offside toggle</button>
<!-- Off-canvas element -->
<nav id="my-menu">
<ul>
<li><a href="#">Home</a></li>
<li><a href="#">About</a></li>
<li><a href="#">Projects</a></li>
<li><a href="#">Contact</a></li>
</ul>
</nav>
<!-- Your Content -->
<div id="my-content-container">
...
</div>
Offside.js is designed to work with your existing HTML.
It doesn't pre-requires any specific markup. When Offside initializes It just adds a few classes on existing DOM elements.
<!-- Put this right before the </body> closing tag -->
<script>
//Offside.js minimal setup
var myOffside = offside( '#my-menu', {
slidingElementsSelector:'#my-content-container',
buttonsSelector: '#my-button, .another-button',
});
</script>
slidingElementsSelector
is a selector list of all elements which slide out when an off-canvas element slides in. It's usually the page wrapper.
Use it only when you need your page to slide together with you off-canvas element.
var myOffside = offside( '#my-menu', {
// Global offside options: affect all offside instances
slidingElementsSelector: '#my-content-container', // String: Sliding elements selectors ('#foo, #bar')
disableCss3dTransforms: false, // Disable CSS 3d Transforms support (for testing purposes)
debug: true, // Boolean: If true, print errors in console
// Offside instance options: affect only this offside instance
buttonsSelector: '#my-button, .another-button', // String: Offside toggle buttons selectors ('#foo, #bar')
slidingSide: 'right', // String: Offside element pushed on left or right
init: function(){}, // Function: After init callback
beforeOpen: function(){}, // Function: Before open callback
afterOpen: function(){}, // Function: After open callback
beforeClose: function(){}, // Function: Before close callback
afterClose: function(){}, // Function: After close callback
});
Global offside options are set when first Offside instance is created. This happens because Offside factory is created when the first offside()
call occurs.
Offside.js plays well with your application. Each Offside instance exposes the following methods:
myOffside.toggle();
myOffside.open();
myOffside.close();
myOffside.closeAll();
myOffside.destroy();
When the first Offside element is initialized, a singleton Offside factory is created and used to return the first Offside instance. The factory keeps track of all initialized Offside elements.
Offside.js is entirely based on classes injection and custom callbacks. No style is DOM injected. Never!
Classes are injected in just 3 elements:
body
off-canvas elements
sliding elements
Here a brief explanation.
init()
<body class="offside-js--init">
<!-- Off-canvas element -->
<div class="offside offside--left">
<!-- Sliding element -->
<div class="offside-sliding-element>
On first interaction with an Offside instance, offside-js--interact
class is added to body. Sometime useful to avoid unespected CSS behaviours on startup.
<body class="offside-js--init offside-js--interact">
beforeOpen()
afterOpen()
<body class="offside-js--init offside-js--transitions offside-js--is-open offside-js--is-left">
<!-- Off-canvas element -->
<div class="offside offside--left is-open">
beforeClose()
afterClose()
<body class="offside-js--init offside-js--transitions">
<!-- Off-canvas element -->
<div class="offside offside--left is-open">
- Set off-canvas elements width directly into
offside.css
stylesheet. - Replace
offside.css
withoffside-no-css-3d-transforms.css
stylesheet and and setdisableCss3dTransforms
setting totrue
to try the fallback.
If you need to set up a simple off-canvas menu, you might not need JS! This Chris Coyer's post explains a nice solution which relies on CSS :target selector. ie9+ only!
On some old mobile browsers ( as Android 2.2.2 FroYo ) off-canvas elements won't get out the page on page load.
This happens because their internal browser do not officially support CSS transforms (see can I use chart), but, according to my experience, they only support it partially. Infact these browser are able to pass Offside CSS 3dTransform test and do not activate Offside fallback strategy.
Offside instances are normally set to position: fixed
and these browser are not able to apply translate3d
transform to fixed positioned element.
An easy - but simplistic - fix, is to switch .offside
position to absolute
and properly set a relative position to a parent element (of course, it might have an impact on your page layout):
.offside {
position: absolute;
}
Like this:
<!-- Sliding element -->
<div id="my-page-wrapper">
<!-- Off-canvas element -->
<nav id="my-offside-element">
...
</nav>
...
</div>
When an element receives a 3D transform style, It creates a containing block for all its descendants that have been set to position: fixed
or position: absolute
. Read more here.
Some ideas for the future. If you'd like to see any of the following realized, please contribute or open an issue.
- Expose Offside factory initialization method (now called on first Offside instance initialization)
- Customizable Offside classes
- Declare a different set of sliding elements for each Offside instance
- Add an option to let more than one Offside instance open at same time
- Replace GruntJS with npm script tasks
- Replace callbacks with global events (maybe)
- Remove CSS 3D Transform Support check (maybe)
Offside.js is currently actively mantained. Any open issue, pull request, contribution, idea to make Offside.js a better tool are welcome!
Make sure you have node and npm on your machine. When ready, you can install Offside.js dependencies:
npm install
# or
npm run setup
Once everything is set up, work in src
directory and build dist
files using:
npm run watch
# or
npm run build
git checkout gh-pages
git checkout master demos
git checkout master dist
##Versioning
Starting from 1.3.0, releases will be numbered with the follow format:
<major>.<minor>.<patch>
And constructed with the following guidelines:
- Breaking backwards compatibility bumps the major
- New additions without breaking backwards compatibility bumps the minor
- Bug fixes and misc changes bump the patch
For more information on semantic versioning, please visit http://semver.org/.