Understanding and solving the JavaScript/CSS entanglement phenomenon

About a year ago I wrote “The graceful degradation myth” in which I talked about the entanglement phenomenon that occurs when you mix JavaScript functionality with CSS “initial states”. By that I mean, if you’ve got a block of content that is initially hidden via CSS (i.e. display: none;) and is only made visible through JavaScript functionality (like an onclick event), you run the risk of barring access to that hidden content to visitors who don’t have JavaScript running on their browser–if you don’t do it right that is.

Since I wrote that post I came up with a technique that solved the problem (as well as the “flicker” problem that occurs with some fixes). This past week I came up with what I believe is an even better solution which I plan on using in upcoming projects. I’ll share both with you here in this post.

How to layer

Before I get to the solutions, I’d like to touch briefly on the subject of the three layers of separation. Those being of course content (HTML), presentation (CSS), and behaviour (JavaScript). Most people in the web standards community know of these, but what I seldom hear is the idea that one layer should never break the other. See, you start with HTML on top of which you place CSS and then comes JavaScript (if you’re using all three that is, though the sequence of the last two is debatable). When you go from CSS to JavaScript you should never do something in the CSS that relies on the JavaScript. In other words, dependency should be unidirectional–downward. A layer should only be dependent on one that it’s applied to, not the other way around. Therefore, when implementing a show/hide mechanism in the behavioural layer, you should do so in a way that still allows the first two layers to be accessible should the third not be available.

The reason I just covered the three layers of separation is because a lot of JavaScript implementations break the rule of non obstruction. A lot of implementations will hide content in CSS and only make it available through JavaScript, thus tangling the two layers together and breaking the separation model. The following solutions avoid this phenomenon.

The first solution

Create a CSS file that will contain all of the “initial state” rules for your behavioural layer. So for example in the case of a flyout menu system, if all sub-menus with the class name “flyout” are to be initially hidden when the page loads your CSS file would contain the following rule:

.flyout{display: none;}

Then, link the CSS file to your page using JavaScript. That way, if JavaScript isn’t available the CSS file never gets loaded and the rule never gets applied. Thus the content remains visible and accessible. The way I used to do this was with the following line of JavaScript code in the <head> of the page:

document.write("<link rel='stylesheet' href='initial_states.css' type='text/css' \/>");

The problem with this technique is that I’m using document.write() which is bad. It’s bad because it ties the instruction to a specific place in the document, it’s archaic and isn’t supported in pure XHTML implementations (such as this site that’s delivered with the application/xhtml+xml MIME type).

The better solution

The better solution builds on the basic concept of the original but does it without document.write(). This time your initial state CSS rules will look like this:

body.hasJS .flyout{display: none;}

And you can go ahead and load the CSS file in the traditional way without using JavaScript. The key rather is to assign the “hasJS” class to the body element through JavaScript. If JavaScript doesn’t exist, it doesn’t get set and the rule doesn’t get applied. You can still keep the initial states in a separate file if you’d like but it isn’t necessary. So long as the rule exists somewhere. The simplest implementation of this technique is to have the following line of JavaScript code on the first line inside the body element:

document.body.className += "hasJS";

The reason for this is because doing it in an onload event will cause a flicker where the page will load, then the content will be hidden. This way, the class is applied before any content is parsed. There are of course better ways of applying the class name (such as an addClassName() function that only adds the class name if it doesn’t already exist).

I haven’t fully tested the better technique on a wide variety of platforms as I have with the standard one, so if you have any success with it, please let me know.

I’ve mocked up a quick example page so you can see it in action.

Tags:


redtube downloader redtube video download redtube video download redtube videos download redtube xvideos xvideos downloader xvideos video download xvideos video download xvideos videos download xvideos metacafe metacafe downloader metacafe video download metacafe video download metacafe videos download metacafe xhamster xhamster downloader xhamster video download xhamster video download xhamster videos download xhamster daylimotion daylimotion downloader daylimotion video download daylimotion video download daylimotion videos download daylimotion facebook facebook downloader facebook video download facebook video download facebook videos download facebook badjojo badjojo downloader badjojo video download badjojo video download badjojo videos download badjojo dachix dachix downloader dachix video download dachix video download dachix videos download dachix keezmovies keezmovies downloader keezmovies video download keezmovies video download keezmovies videos download keezmovies shufuni shufuni downloader shufuni video download shufuni video download shufuni videos download shufuni vimeo vimeo downloader vimeo video download vimeo video download vimeo videos download vimeo veoh veoh downloader veoh video download veoh video download veoh videos download veoh theync theync downloader theync video download theync video download theync videos download theync ehow ehow downloader ehow video download ehow video download ehow videos download ehow xtube xtube downloader xtube video download xtube video download xtube videos download xtube stupidvideos stupidvideos downloader stupidvideos video download stupidvideos video download stupidvideos videos download stupidvideos AccessHollywood AccessHollywood downloader AccessHollywood video download AccessHollywood video download AccessHollywood videos download AccessHollywood ClipJunkie ClipJunkie downloader ClipJunkie video download ClipJunkie video download ClipJunkie videos download ClipJunkie Ebaumsworld Ebaumsworld downloader Ebaumsworld video download Ebaumsworld video download Ebaumsworld videos download Ebaumsworld FunnyOrDie FunnyOrDie downloader FunnyOrDie video download FunnyOrDie video download FunnyOrDie videos download FunnyOrDie FootyTube FootyTube downloader FootyTube video download FootyTube video download FootyTube videos download FootyTube pornhub pornhub downloader pornhub video download pornhub video download pornhub videos download pornhub