Unobtrusive JavaScript

Explains the notion of Unobtrusive JavaScript, Layering, and Separation of Concerns.

It is considered a best practice to separate web pages into three areas of concern: content (HTML), style (CSS), and behavior (JavaScript). It makes these pages better organized, more understandable, and easier-to-maintain.



Essentials


The term Unobtrusive JavaScript refers to how you use JavaScript on web pages. The unobtrusive part denotes out-of-the-way, discreet, and without interference. Initially it meant that if a browser did not support certain features or if JavaScript had been disabled the user would not be shut out. If possible, JavaScript would run, but if not then the site would continue to present the necessary information. This approach is also referred to as progressive enhancement.

More recently however, the role of JavaScript has become so critical that many new sites simply cannot function without it and therefore most developers pretty much ignore the possibility of JavaScript not being available. For example, single page applications (SPAs) that rely on Ajax to perform partial page refreshes will simply not work without JavaScript.

However, the concept of unobtrusive JavaScript lives on as a way of structuring web pages; this time from the perspective of the developer and how they layer (i.e. separate) their code. The idea is that JavaScript should not be embedded with HTML, but rather there needs to be a separation of behavior (JavaScript) and content (HTML).

In many web pages you see JavaScript assigned to an onclick attribute on a DOM element, like so:

<button onclick="alert('Hello');return false;" >Click me</button>

This works well on pages with just a few JavaScript snippets, but when your application starts to grow and you have hundreds of DOM elements across many pages that require, say, JavaScript client-side validation, then it becomes very difficult to maintain. This is why it is best to separate the JavaScript from the HTML.

The notion of separating web pages in layers has another dimension: styles (using CSS). These three dimensions: behavior, style, and content are frequently referred to as the three layers of web design. Here is a graphic of these layers.

Notice in the figure that each layer has its own file type: HTML resides in .html files (or something else depending on the technology used), JavaScript in .js files, and Style Sheets in .css files. This greatly facilitates a clean separation of concerns.

Here is an example of the three layers:

HTML
<div class="area">
   <button id="clicker">Click here</button>
</div>
JavaScript
$(function() {
     $("#clicker").on('click', function() {
         alert("Yep, clicked!");
     });
}
CSS
.area {
   padding:10px;
   background:lightblue;
}


The benefits of organizing your pages in separate layers are numerous:

  • Increased Reusability. The CSS style sheets and JavaScript code you write for one page is reusable at other pages. Pages that have CSS styles and JavaScript embedded in the HTML will not be reusable for those components.
  • Easier to Maintain. If you need to correct a mistake or make enhancements it is usually clear where, in which file, to go. If it involves behavior it is a JavaScript file, if it is the look and feel it is a CSS file, or else it is a web page's HTML itself. Furthermore, if styles and behaviors are reused at multiple pages fixing it for one instance will most likely also fix it for all other instances.
  • Team development. Web app creation may involve people from different disciplines: developers, designers, information architects, usability experts, etc. With the separation of layers, each can work on their own file type and not interfere with other people's work.
  • Better Performance. Once your browser has loaded a CSS or JavaScript file, it will keep it cached between pages. If each page had its styles and scripts embedded in the HTML it would need to re-load this for each new page request.
  • Improved accessibility. External style sheets and script files are easier ignored if the browser cannot handle these (or is configured not to handle these). This is called progressive enhancement, in which the pages are designed to enhance the user experience as much as possible, but the baseline is still a usable page. The baseline will be HTML with text, images, and controls which every browser supports. Then if CSS is supported (which all do today) then the CSS files are served up. Finally, if JavaScript is not disabled then these files are loaded as well.

Concerning the last point, this is less and less an issue today. Browser makers are beginning to push users to upgrade more quickly to more recent browser versions. All browsers today accept HTML, CSS, and JavaScript. In fact, we are on the cusp of the next stage: HTML5 and CSS3. Right now, we are beginning to see developers writing HTML5 and CSS3 web apps knowing that, for the time being, they will miss out on customers that do not keep up with their browser versions. Hopefully, their content and presentation is so compelling that it will spur a worldwide flurry of browser upgrades which would make any web developers very happy.

As an aside, when using an MV* framework (MVC, MVP, MVVM) you typically also use a templating engine (such as mustache.js, underscore.js, or the built-in jQuery templating engine). In those cases the data is dynamically injected into the HTML and maintained by data binding. This is a very powerful concept and another step in facilitating the aforementioned separation of concerns. MV* frameworks are discussed in the Model View Pattern section. Templating is demonstrated in the 'Patterns in Action' section.