Unison.js

Unifying named breakpoints across CSS, JS, and HTML
Toggle breakpoint info View on GitHub

What is Unison.js

Unison.js is a small plugin (1.2kb minified) that allows you to declare named breakpoints in one place and automatically sync them across your javascript and markup. When all of your front-end technologies share breakpoint information, complex responsive tasks such as conditional loading and image swapping become much simpler and straight-forward.

How does it work

To take full advantage of Unison.js, you'll need to be using a css pre-processor such as SASS, LESS, or Stylus. To begin, declare your breakpoints in your breakpoints partial as you normally would:

// SASS
$usn-x-small         : 200px;
$usn-small           : 400px;
$usn-small-medium    : 600px;
$usn-medium          : 800px;
$usn-large-medium    : 1000px;
$usn-large           : 1200px;
$usn-x-large         : 1400px;

// LESS
@usn-x-small         : 200px;
@usn-small           : 400px;
@usn-small-medium    : 600px;
@usn-medium          : 800px;
@usn-large-medium    : 1000px;
@usn-large           : 1200px;
@usn-x-large         : 1400px;

// STYLUS
$usn-x-small         = 200px
$usn-small           = 400px
$usn-small-medium    = 600px
$usn-medium          = 800px
$usn-large-medium    = 1000px
$usn-large           = 1200px
$usn-x-large         = 1400px

These are the breakpoint names that you'll use in your markup and javascript to trigger events as well. This is the only place in your project that you'll need to declare your breakpoints. Whenever these values change, they'll be synced across your code automatically. After you've declared your breakpoints, you'll need to include the names in a second block so the CSS can pass them to the javascript.

// SASS
$mq-sync:
  usn-x-small        $usn-x-small,
  usn-small          $usn-small,
  usn-small-medium   $usn-small-medium,
  usn-medium         $usn-medium,
  usn-large-medium   $usn-large-medium,
  usn-large          $usn-large,
  usn-x-large        $usn-x-large
;

// LESS
@breakpoints: "usn-x-small @{usn-x-small}",
              "usn-small @{usn-small}",
              "usn-small-medium @{usn-small-medium}",
              "usn-medium @{usn-medium}",
              "usn-large-medium @{usn-large-medium}",
              "usn-large @{usn-large}",
              "usn-x-large @{usn-x-large}";

// STYLUS
$mq-sync = usn-x-small        $usn-x-small,
           usn-small          $usn-small,
           usn-small-medium   $usn-small-medium,
           usn-medium         $usn-medium,
           usn-large-medium   $usn-large-medium,
           usn-large          $usn-large,
           usn-x-large        $usn-x-large

This bit of code may look redundant, but it's required to broadcast the names of each breakpoint outside of your stylesheet. As mentioned in the comments of the breakpoint file, if you ever change the name of your break point, you'll have to update it in this block as well. Once you've named and declared your breakpoints, place the Unison.js script on your page:

<script src="unison.min.js"></script>

And that's all there is to it! Your named breakspaces are now available in any of your javascript files. To test, open your javascript console and type Unison.fetch.all(). If everything is set up correctly, the console will return an object containing a hash of the breakpoints you declared in your breakpoints file. If your CSS is not correctly passing breakpoint variables, Unison.fetch.all() will return null.

Behind the scenes

The breakpoints file is using the font-family property on the page's head and title tags to store information. For each breakpoint you set, the current value is set and updated on your head tag, while the full hash of breakpoints is stored in the title tag. Unison.js simply parses the font-family property of each tag and stores them as a globally-accessible object. Simple and efficient!

Displaying breakpoint data

While building out your responsive design, it's helpful to see which breakpoint you're currently working with, and Unison.js makes that data easily available. Simply set the debug variable to true in your breakpoints file and your current breakpoint data will be appended to your page for easy debugging. To see this in action, click the "Toggle breakpoint info" button at the top of the page and resize your browser.

Acessing breakpoint data in your javascript

The Unison object is globally available, which allows you to easily access your breakpoint data with the Unison.fetch method.

var allBreakpoints = Unison.fetch.all();

// allBreakpoints = {
//   usn-x-small      : "200px",
//   usn-small        : "400px",
//   usn-small-medium : "600px",
//   usn-medium       : "800px",
//   usn-large-medium : "1000px",
//   usn-large        : "1200px",
//   usn-x-large      : "1400px"
// }

var currentBreakpoint = Unison.fetch.now();

// currentBreakpoint = {
//   name   : "usn-large",
//   width  : "1200px"
// }

var currentBPval = parseInt(Unison.fetch.now().width);

// currentBPval = 1200

Breakpoint events

Unison.js allows you to add breakpoint listeners in your javascript using the Unison.on() function. The declared functions will fire every time the screen is resized to the size specified in your breakpoint file. This is done without using matchMedia, which makes it compatable with IE9.

This page is currently running the following listeners

Unison.on('usn-medium', function() {
  console.log('medium breakpoint');
});
Unison.on('usn-small', function() {
  console.log('small breakpoint');
});
Unison.on('usn-medium', function() {
  console.log('another medium function');
});

There's also a generic Unison.on('change') event that will fire whenever the breakpoint changes and return the new breakpoint's data to your callback function. This page is using:

Unison.on('change', function(bp) {
  console.log('breakpoint changed!');
  console.log(bp);
});

The Unison.on('change') allows you to easily organize your breakpoint-specific functions.

Unison.on('change', function(bp) {
  switch ( bp.name ) {
    case 'usn-small':
      mySmallBreakpointFunction();
      break;
    case 'usn-medium':
      myMediumBreakpointFunction();
      break;
    case 'usn-large':
      myLargeBreakpointFunction();
      break;
  }
});

Conditional loading with Responsive Comments

To showcase the utility of Unison.js, we decided to refactor one our favorite responsive design tools, Adam Chambers' Responsive Comments, so it could take advantage of synced breakpoints. If you're not familiar with it already, Responsive Comments is an ingenius javascript plugin that allows client-side conditional loading, instead of relying on media queries alone or server-side detection (e.g. RESS). By hiding bandwidth-heavy modules in simple HTML comments, and only loading them once the screen has hit a certain breakpoint, you can increase the performance of your mobile experience significantly. To that end, we created our first Unison.js plugin: unison-responsive-comments.js.

Using the same named breakpoints that we declared in our original _breakpoints.scss file, we can now specify which modules we want to load conditionally based on the our current breakpoint right in the markup. We've included three pictures of Björk below this paragraph that are conditionally loaded only when a certain named breakpoint is fired. All you have to do is specify the breakpoint in your markup in a data-usn-load-if attribute.

<div data-usn-load-if="usn-medium">
  <!--
  <hr/>
  <div class="m-bjork medium">
    <img src="img/medium.jpg" />
  </div>
  -->
</div>

NOTE: If you resize your browser back and forth, you will notice that the larger photos load in once you pass a breakpoint, but don't disappear when you resize to a smaller width. That's intended behavior. Conditional loading is not a replacement for media queries; it's sole responsibility is loading in content when a breakpoint is met, not hiding it at smaller sizes.

Another powerful feature of Responsive Comments is the ability to tie custom events to conditionally-loaded content. We've added IDs to the largest and smallest Björk pictures, and fire a message to the console whenever they're successfully loaded into the DOM.

Unison.ConditionalLoad.loads('large-bjork', function() {
  console.log('The large photo of Björk loaded successfully!');
});
Unison.ConditionalLoad.loads('small-bjork', function() {
  console.log('The small photo of Björk loaded successfully!');
});

Acknowledgements

Unison.js is influenced by Brett Jankord's Media Query Sync.

Disclaimer

This plugin should be considered beta. We haven't had a chance to test it fully across older browsers, but it should perform fine on modern browsers (IE9+).

License

The MIT License (MIT)

Copyright (c) 2014 Dan Chilton

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.