X

Geertjan's Blog

  • June 7, 2015

From Responsive CSS to Responsive JavaScript with Response.js & Knockout.js

Geertjan Wielenga
Product Manager

More often than not, you use CSS media rules to specify whether something should be displayed based on screen resolution. For example, imagine you have a logo which you'd rather not display on smaller devices because you want that real estate for other things:

@media (min-width: 481px) {
.logo:before {
content:url("images/coca_cola_logo.png");
display: block;
text-align:center;
}
}
@media (max-width: 480px) {
.logo:before {
display: none;
}
}

And then you use the logo class as follows: 

<div>
<a class="logo" href="http://cocacola.com"></a>
</div>

However, when the width of the screen is less than 480, the logo is still loaded, you can see it in the DOM, e.g., in the Browser DOM window in the IDE, though it is not being used—it is simply hidden from the view:

Imagine that you could dynamically swap content based on breakpoints and data attributes. That's what Response.js is all about. For this specific example, with a single logo, setting up a content swapping solution is overkill. But imagine you have heaps of logos and other items that need to be displayed or hidden or resized based on screen size. Also, imagine you're using some heavy JavaScript loading solutions, such as Google Maps, which you'd like to have available for large screen sizes, though not for mobile devices. By default, all those JavaScript libraries and other artifacts would be loaded even though they'd never be used, the Google Maps viewer would simply be hidden from the HTML view whenever you decide to exclude it. That's potentially a massive waste of resources, e.g., battery life, on a small device.

Simply delete your CSS media rules, e.g., the ones shown above. Rewrite the CSS logo class to the following, i.e., now there's no CSS rule, simple a class:

.logo:before { 
content:url("images/coca_cola_logo.png");
display: block;
text-align:center;
}

Then include "responsejs" in your Bower file:

"dependencies": {
"knockout": "3.3.0",
"requirejs-text": "2.0.14",
"requirejs": "2.1.17",
"bootstrap-dropdown": "*",
"jquery": "2.1.4",
"responsejs": "0.9.1"
}

Register and use it as follows:

require.config({
baseUrl: './',
paths: {
knockout: './js/libraries/knockout/dist/knockout',
text: './js/libraries/requirejs-text/text',
jquery: './js/libraries/jquery/dist/jquery',
response: './js/libraries/responsejs/response',
initComponents: './js/initComponents'
},
// Shim configuration for modules that do not expose AMD:
shim : {
'response':{
deps: ['jquery']
}
},
waitSeconds: 2
});
require(['knockout', 'initComponents', 'response'],
function (ko, initComponents) {
var self = this;
self.weAreSmall = ko.observable();
Response.create({
breakpoints: [0, 480, 481]
});
Response.action(function() {
if (Response.band(0, 480)){
self.weAreSmall(true);
} else {
self.weAreSmall(false);
}
});
ko.applyBindings(new initComponents());
}
);

(Note: The above comes from Solid Knockout.)







Take note of "Response.create" and "Response.action" above. You've now set your "weAreSmall" observable, based on the breakpoint that Response.js handles for you.

Now go back to the element in the view where you use your 'logo' CSS class. Use the "ko ifnot" construct (which, yes, looks weird because it looks like a comment, but it's not, that's simply the way you can introduce if clauses via Knockout) into your HTML view:

<!-- ko ifnot: weAreSmall -->
<div>
<a class="logo" href="http://cocacola.com"></a>
</div>
<!-- /ko -->

You're now using your 'weAreSmall' observable to specify whether the logo is displayed or not. When you look in the NetBeans DOM Browser window, you'll see that there's no div (instead of a hidden logo) when the device size is smaller than 480 px. Compare the screenshot below to the one above, i.e., the logo is not in the DOM anymore, as can be seen in the Brower DOM window in the IDE:

Magically, thanks to Response.js, the logo is swapped back into the DOM when the resolution changes:

The above explanation and all the code comes from around the 20th minute of this recording of a session I did at JavaOne last year with JB Brock. (And we won a Duke's Choice Award for it.) From around the 20th minute, you'll see the above explained excellently by JB, you'll see the Google Maps scenario outlined above, and you'll also see all the code above, all written by JB, again.

Also, note that I have updated Solid Knockout to include the code above, i.e., it now includes Response.js, together with all the sample code above.

In summary, you've now learned how to move from responsive CSS to responsive JavaScript.

Be the first to comment

Comments ( 0 )
Please enter your name.Please provide a valid email address.Please enter a comment.CAPTCHA challenge response provided was incorrect. Please try again.