How to hide and show initial content, depending on whether JavaScript support is available

Many people ask me how I choose to address an situation where all content in a web should be available without JavaScript, but certain parts hidden if JavaScript is enabled. It's a pretty common scenario where, for instance, part of a tree navigation or different blocks in the web page are hidden for JavaScript-enabled web browsers, thus letting the end user toggle them. However, if the end user doesn't have JavaScript enabled or if it fails for any reason, you would want that toggled content to be visible immediately.

Using noscript?

Just use the noscript element, I guess you're thinking. While that definitely works to some degree, there are some issues with it. To begin with, content within the noscript element will only be visible to user with JavaScript disabled. Not applicable if you want the content visible to everyone, and then having the interaction presentation enhanced with JavaScript. Second, noscript only tells you if JavaScript is enabled or not in the web browser; not if it actually works. There are proxy servers out there cleaning out JavaScript files with what it thinks is inappropriate content, over-zealous antivirus programs, firewalls preventing certain functionality, and so on. In my pragmatic mind, this pretty much renders noscript useless, if you want to be a 100% sure.

Server-side solution?

Not really. You can check USER_AGENT headers and hope for luck, but it's not a guarantee nor offering a consistent way. What you can do is to add some small JavaScript in your web page, which redirects the page or sends a form or XMLHTTPRequest to the server, which in turn stores the value in a cookie or session variable. Then you can reference that on the server-side for consecutive calls. This adds up to extra JavaScript and server-side functionality, which, to me, sounds like making it overly complicated for JavaScript detection.

Hiding of elements

I think the most popular way nowadays is to run JavaScript code at the bottom of a web page, and through a JavaScript library's way to determine if the DOM has finished loading or just by using inline JavaScript code, make a call to hide content which should only be initially visible to the end users with JavaScript disabled. Examples:

The downside

The problem with this approach, however, is that between the point of your HTML that is to be hidden, and the point where your JavaScript library has been completely included and then found the element(s) to hide, there is a possible discrepancy which will result in "jumping" pages; i.e. you will get a flicker temporarily showing the content, and then hiding it. Not acceptable. Looking at the above sample code, this behavior occurs for both DOMAssistant, jQuery and Prototype in, amongst others, web browsers like Internet Explorer 6. The only solution where it doesn't consistently jump is when the code is directly inline, but it does seem to occur the first time that page is loaded in a web browser as well.

A little disclaimer and explanation

The work amongst JavaScript libraries to detect when the DOM has actually loaded is indeed implemented in a solid way. The problem above is the inclusion of the JavaScript file later in the code than the HTML that is to be hidden. If we were to move up the inclusion of the JavaScript file to the top of the document to the head section, no jumping would take place. Without going into the discussion Where To Include JavaScript Files In A Document, the point here is to show how just one extra HTTP request will slow down the perceived rendering. Imagine a more real page where you have image inclusion, other dependencies making their requests, or even horrible ad scripts using document.write creating iframes, who in turn load some external content (a reality for way to many people). With such scenarios, there is no rock solid way to prevent certain content from jumping, no matter how optimized your JavaScript code is to check if the DOM has loaded.

A proposed solution

Working back and forth with this, I was looking for a solution that is completely consistent and reliable, while still offering code separation and caching between pages in a web site. What I came up with, if I may say so myself, is quite simple and clever. :-)

Using JavaScript to include another style sheet

The solution is to include a JavaScript file in the head part of the document. If JavaScript is enabled, it directly runs an anonymous function that in turn creates a link element which only contains CSS code to hide chosen elements if JavaScript is enabled. The way web browsers work, is that JavaScript files has to completely load before any further parsing will take place. This means that when the parsing of the actual content within the body element takes place, your CSS has already been included, hence it's as if the dynamically applied style has always been there. And, the beauty of all this is that by following some of the advice presented in Improve Your Web Site Performance - Tips & Tricks To Get A Good YSlow Rating, is that if you use Expires headers in a proper manner, there will only be one request, site-wide, for your JavaScript and CSS files taking care of your problem. From then on, it reads it directly from your local web browser cache.

The code

I've put together a little demo page to show JavaScript inclusion of a CSS file. Breaking down the code, here are the vital parts: First, include the JavaScript file:
<head>
	<title>Using a script to include a CSS file</title>
	<script type="text/javascript" src="script-styles.js"></script>
</head>
This is the anonymous function running in its own scope, preventing clashes with other variable names. Just change the path to the CSS file to whatever suits you:
(function () {
	var head = document.getElementsByTagName("head")[0];
	if (head) {
		var scriptStyles = document.createElement("link");
		scriptStyles.rel = "stylesheet";
		scriptStyles.type = "text/css";
		scriptStyles.href = "script-styles.css";
		head.appendChild(scriptStyles);
	}
}());
And, lastly, create the script-styles.css file and add the necessary CSS for the version of the web site intended for end users with JavaScript enabled:
#hide-with-script {
	display: none;
}

No more jumping!

With this solution, no matter how many other dependencies of other external files you might have in your web page/site, I hope to have offered you a way to hide extra content for people with JavaScript-enabled web browsers, while offering all of the content to those with JavaScript disabled.
Posted in CSS,Developing,DOMAssistant,JavaScript,Technology |

63 Comments

  • Steven Clark says:

    Nice idea Robert, we'll actually be using this in our project I'd say. A member of our team has been looking for a solution that fit our needs for a university project – accredited that you're the solution's author of course.

    Ha its funny how at the 11th hour sometimes a fast and more logical solution just drops out of the sky into an RSS Reader.

    Thanks :)

  • icaaq says:

    I don’t get it, first you say:

    The problem above is the inclusion of the JavaScript file later in the code than the HTML that is to be hidden. If we were to move up the inclusion of the JavaScript file to the top of the document to the head section, no jumping would take place.

    Then you say:

    The solution is to include a JavaScript file in the head part of the document.

    I use jquery in the head to add a class on the body. works like a charm :)
    $(function() {
    $("body").addClass("js");
    });

    From there I can hide anything I want just using the .js class.
    .js #content{
    position: absolute;
    left: -999em;
    }

  • It's a problem I've been lately trying to solve myself. My solution is almost identical, although I am not linking an extra stylesheet, but I add a class to the <code><body></code> element. Code looks like this:

    <code>(function(){

    var interval = window.setInterval(function(){

    var b;

    if (b = document.getElementsByTagName("body")[0]) {

    b.className += " jsEnabled";

    window.clearInterval(interval);

    }

    },50);

    }());</code>

    It's called in the head, so I've added interval to check if body is already available. Thanks to this approach I can keep all my styles in one stylesheet, e.g.

    <code>#your-element { display: block; }

    body.jsEnabled #your-element { display: none; }</code>

  • Marco says:

    I use the same solution as Krzychu Danek . Works like a charm!

    All I have is:

    <script type="text/javascript">

    document.getElementById('body_id').className = 'js';

    </script>

    right after the body start tag.

    Where body has id 'body_id'.

  • Ole says:

    I had the same problems with flickering content. I googled the whole web ;-) and found such a simple and easy solution from “Wojciech Bednarski“. It has the same approach like the one from Krzychu Danek, but it’s much more simple.

    Here we go:
    Put this in an external JS-File or directly in the head-section of a document:
    document.documentElement.className += " mbbJsLoad";
    This puts a className in the <html>-Tag of a document. So i can be sure it is present BEFORE the site is loaded!

    In the CSS-File, i can now make a reference to that specific ClassName:
    .mbbJsLoad .elementToHide {
    display:none;
    }

    It works lika a charm!

  • Very clever. In a recent project I am adding special CSS classes to the element to style it differently depending on the presence of Javascript or not, but I was still waiting to see the effects of the problem you described.

    Keeping an eye on this one ;-)

  • Robert Nyman says:

    Steven,

    Good to hear! Naturally, you're free to use it any way you want. Giving credits to me is nice, but not necessary. :-)

    Krzychu,

    Absolutely, that's another option. The upside is that you're using only one style sheet, the downside, is the need for an interval check. What I fear with the <code>setInterval</code> solution is that it is an unnecessary load for the web browser, and that, at least in theory, there's a risk that your supposed-to-be-hidden element might show up in between those intervals being called.

    Personally, I prefer the separation into its own CSS, to be able to tell the difference between the JavaScript-enabled and the Javascript-disabled solution; and, by using Expires headers, it's a one time request, site-wide.

    Marco,

    Good to see that you are still reading! :-)

    That should work fine, too. What I might consider being less optimal is that by adding a class to the <code>body</code> element after it has already started rendering might trigger some sort of re-rendering. Also, I'd prefer the <code>body</code> of my documents not to start with a <code>script</code> element.

    icaaq,

    As mentioned in the post, having the scripts at the bottom in the demos are just to show how any other dependency might cause a rendering delay (besides from the point that stalling the entire loading of the page by including a complete JavaScript library in the <code>head</code> section is seldom best practice).

    Your solution will definitely work fine, but there are two factors that I'd like to emphasize about my proposed solution:

    1) No need of loading one or several large files in the <code>head</code> section, before the rendering of the <code>body</code>.

    2) This solution is context-independent; meaning it's not dependent on any JavaScript library, and no matter how much your web page contains, it will work consistently and flawlessly.

    Jeroen,

    You do that! :-)

  • Marco says:

    @icaaq

    So what happens when JQuery hasn't loaded yet? Jumping?

  • Andreas says:

    I've always gone with the JS-class in the body-element. I've used jQuery quite a lot but for this to be as quick as possible something like:

    <body id="home-page">

    <script type="text/javascript">document.body.className = 'js';</script>

    … other code

    Works pretty well.

  • @ Ole

    Just keep in mind that applying class to <code><html></code> element results in invalid HTML according to w3c specs (http://www.w3.org/TR/html401/struct/global.html#h

    @ Robert

    Yes, setInterval has it downfalls, but as far as I know it's how most JS frameworks handle their domready functionality (I might be wrong though). What is more a friend pointed me to a following setInterval Firefox bug yesterday – Firefox setInterval bug test case.

    All in all, I don't think there's an optimal solution if we want to stick to the following guidelines:

    – put all your scripts in external files and include them at the bottom, so your <code><body></code> loads without delay

    – make sure everything works without JS enabled

    – avoid page flicker

    – keep your HTML requests at minimum

  • packed.it uses the same concept.

    it loads JS dedicated CSS (libraries or other stuff) only for browsers that have JS enabled.

    If your browser supports JS, it will load libraries/fx dedicated CSS, otherwise it will load only basic CSS

    I call them graceful enhancement :)

  • Robert Nyman says:

    @Marco,

    icaaq's code will work fine, since jQuery has to completely load before the body begins to load. However, from my point of view, it's an unnecessary impact on the end user.

    Andreas,

    Yes, but see my concerns above in reply to Marco about that approach.

    Ole,

    It's an interesting solution, although, as Krzychu pointed out, it's invalid, and I'm thinking that there might be a risk with this to get it consistent across web browsers and platforms.

    Krzychu,

    Thanks for the link!

    I think it varies between JavaScript libraries what way to check if the DOM has loaded. With DOMAssistant, we use a modified version of the solution by Dean Edwards and others.

    I agree that it's hard to find anything optimal in regards to the guidelines you describe. My thinking with my suggested solution is that the only real downside is two extra HTTP requests. However, with Expires headers, this is a one time hit, for an entire web site, which makes it an ok solution for me.

    Andrea,

    Graceful enhancement. I like that. :-)

  • I also just add a classname to body, details are not that different from some of the other solutions.

  • Ole says:

    @Krzychu Danek

    I tried your solution with the setTimeout. It worked good in Firefox but in IE7 and IE6 there was still flickering (because of 50ms timeout?). Maybe because i've tested local?

  • Really great post!

    I've actually used something similar in a project at work. The css looks like this:

    <code>

    #myService {

    background:#f00;

    }

    #myService.JSEnabled {

    background:#00f;

    }

    </code>

    We then use a general function to enable the JS-enabled CSS to the service:

    <code>

    // added to domReady/dom:loaded/ready

    function prepareMyService() {

    // some code to enhance the service

    enableJSStyles( myServiceElem );

    }

    function enableJSStyles(elm) {

    elm.className += " JSEnabled";

    }

    </code>

    Works like a charm. We also use a class JSDependent to to something similar to JS-only services (that is, no fallback):

    <code>

    .JSdependent {

    display:none;

    }

    </code>

    We simply removes the classname JSDependent from the service-wrapper.

  • Arjan says:

    I actually saw the <code>div</code> element you hide, only a few moments, but still I saw it. I think that is because you use an external <abbr title="Cascading Style Sheets">CSS</abbr> file, that also need to be loaded.

    What I don't really get is, you change the <abbr title="Document Object Model">DOM</abbr> with that script, before the <abbr title="Document Object Model">DOM</abbr> is completely parsed? I thought that was not possible, but it seems I was mistaken. I usually use an evil <code>document.write('<link …>');</code> to achieve a similar effect. The method you describe is, of course, a much better solution.

  • @Ole

    Hmm, I'll have to give it a bit more testing then. Thanks for the tip.

  • Den Odell says:

    Great write up, Robert.

    Funnily enough, I had come to the exact same conclusion as you a few months back and implemented it on the Nike Playmaker website.

    Just like yourself, I include a script tag pointing to 'add_js_css.js' within the head, and that JS file contains the code necessary to dynamically load an additional stylesheet.

    Great technique, and very useful.

    Thanks again.

    Den Odell

    //AKQA

  • Robert Nyman says:

    Anders,

    I’m sure that works like a charm, given that the JavaScript library of your choice is included in the head section, and that no weird dependencies using document.write slow down the rendering of the page.

    Arjan,

    If you stress the page with multiple reloads before the previous has finished loading etc, you can force the element visible. But I don’t think that’s because it’s an external file, because that would then mean that any other CSS included above would also fail at times.

    If there are situations where this would occur consistently, I guess, like you mention, resorting to document.write would be sufficient to cater to that problem.

    And yes, it is possible to manipulate parts of the DOM before the entire DOM has loaded.

    Den,

    Thanks! Great minds think alike. :-p

    Andreas,

    Sorry, I misunderstood you above.

    I don’t share your opinion about flickering, though, and definitely oppose “Flickering is a result of doing JS properly”. I think it can, and should, be avoided at all times, and I also doubt most users accept flickering.

    Like with AJAX responses: if you have AJAX calls immediately when the page load, you can use the above solution to hide fallback content so it doesn’t flicker. However, if you have a solution where AJAX calls might be made by the user clicking something, for instance, then the wanted result can be to replace existing content in the page. But I wouldn’t really refer to that as flickering, but rather dynamic content updating (which would go well together with a “loading” dialog or so, indicating that things will change).

    And, maybe that was what you meant with acceptable flickering, and I misunderstood you (again). :-)

    And, thanks for using FlashReplace! :-D

  • Andreas says:

    @Robert – My example didn't use jQuery though. Only about 70 bytes of code needs to be loaded and executed and it happens straight after the opening body-tag so the result is minimal flickering.

    Or am I missing something?

    In some cases, though, you can't simply use a class in the body-element. Sometimes you want to replace entire elements with ajax-responses (or whatever) but in these cases I don't care about the flickering. Flickering is a result of doing JS properly. I believe most users are aware (or at least will be eventually) of why this happens.

    I'd rather follow best practices and put all my JS in one (and only one) external JS-file than hack to get rid of the flicker. One hack I'm willing to use though is the one I explained before. It won't slow down page-rendering more than a milisec and it's very handy to have a js-class.

    I normally put a "no-js" class in the body-element and then change it to "js" using JS. Sometimes it can be handy to style things based on JS being disabled:

    body.no-js #foo {}

    body.js #foo {}

    Speaking of classing and ID:ing the body-element, I normally use quite a few other classes as well.

    One #id that explains what type of page we're on (#article-page, #contact-page, #article-listing-page, #etc-page), one js-disabled/js-enabled, one flash-enabled/flash-disabled (using FlashReplace :)), and a couple of weather/time-classes (.sunny .mid-day).

  • A striped down version of sifr:s way to do it. Run this somewhere in the head and then you can style on .hasJavascript

    var node = document.documentElement;

    if(node.className == null || node.className.match(/hasJavascript/) == null){

    var append = "hasJavascript";

    var className = node.className;

    node.className = className == null ? append : className.replace(/s+/g, " ") + (className == "" ? "" : " ") + append;

    }

    works in all modern browsers as far as I know, and whiteout any additional js-libs. Why care about a potentially not loaded body when you can place the style on the document-element? ;-) I know that some people would say that this will generate invalid html, but it is not written in html, but generated by the DOM and as long as the DOM supports it is valid for the current implementation. And as far as I can see there is nothing in the standard that shall restrict this.

  • Robert Nyman says:

    Martin,

    This solution has been mentioned and discussed above. Why would someone want an invalid implementation, where the code in this post does the same thing, but in a valid manner (and also without the need to check for a <code>body</code> element)? :-)

  • Andreas says:

    But if best practice is to only include one JS-file at the bottom of the page then I don't see how you could fix flicker-problems with added/changed content and follow best practices at the same time.

    Hiding content that is already in the markup is easy with a JS-class in body (or your stylesheet solution), but what about when you add content using JS? Then how do you avoid flickering?

    The only way I can think of is to run the script the second the element that is being "scripted" loads:

    <code>

    <div id="recent-comments">

    </div>

    <script type="text/javascript" src="/js/recent-comments.js"></script>

    </code>

    But then you'd end up with plenty more than one JS-file and they'd be spread out all over the place.

    One other solution is to include scripts in the head. Something we all know is bad by now though.

    If I visit a site and it flickers a bit when JS kicks in, and I notice they follow best practices by loading one external JS-file then I welcome the flickering. I know the site is coded well using best practices and progressive enhancement.

    To me trying to hack to get around flickering is like hacking to change the look of select-elements. We shouldn't be doing this. It's the browsers problem it can't run JS faster. It's the browsers problem it can't handle styling of form-controls. It's the browsers problem it doesn't render more than one background-image per element.

    I'd rather have well-structured, optimized code that works today, tomorrow and forever than hacks all over the place to hide browser-related problems that I really shouldn't be bothering with in the first place.

  • Robert Nyman says:

    Andreas,

    If I visit a site and it flickers a bit when JS kicks in, and I notice they follow best practices by loading one external JS-file then I welcome the flickering.

    Well, you might, but the other 99.5% of the population using web sites won't care about what's regarded as good code. Best practices are there to make you're code stable and offer the end user the best experience.

    And that's the thing. I can't see what portion in the scenario you're describing that is a hack. Let's begin with this solution for hiding content: it's rock solid, and follows best practices by using external files. JavaScript files aren't forbidden in the <code>head</code>, they're just not recommended to be there if they're large.

    Moving on to adding content with JavaScript, for instance with AJAX calls updating part of the page: first, I don't refer to that as flickering, but just content updating. You can show small loading messages, flash the newly received content etc to make the experience as pleasurable as possible for the visitor.

    Meaning, you can have your code in just one file following all the guidelines to the letter. It's just about how you choose to give the end user feedback and how content is updated.

  • icaaq says:

    I say: <acronym title="The Web Ain't Print">TWAP</acronym>. Let the page load as it loads :D

  • Andreas says:

    Good points. I know I'm bad at trying to see things from a non-geeky persons perspective.

    I agree that ajax(or not)-generated content based on user-action is not flickering, but simply loading. And I do display loading-messages for all ajax-requests but in some cases I may add links (or whatever) using JS and in those cases I don't see how one could avoid flckering and still use one external JS-file in the bottom of the document.

    My "Random Images", "Blog Roll" and "Random Quote"-modules are examples of where I add a link using JS. Could that be done with less flicker without moving my scripts around?

  • Jrf says:

    Hi Robert,

    Funny to see your post just now. I've been using a similar method for the past two years in a standards compliant menu which I have described in this accessible fold-out menu tutorial.

    I do like the elegance of the head.appendChild(scriptStyles); statement, so I might just update my script & tutorial with that when I can find the time.

  • Mats says:

    Maybe I missed this above but how do you handle showing of the hidden part after the page has loaded?

    I know prototype just adds display: none to things it hides and the simply removes it when it shows things, this approach would keep the hidden elements hidden at all times?

    I've encoutered this before and have been forced to add a style="display: none" attribute to the menu items i wanted to toggle.

    I'm curious what your solution would be for that case.

  • Niklas says:

    When hitting F5 on your demopage (using FF 2.0.0.14) the purple div does flicker.

    I tried the same html but with the script from Martin Odhelius and there is no flickering at all there.

  • Robert Nyman says:

    icaaq,

    Ha ha! :-)

    Andreas,

    It is an interesting thing you touch on there. Such an example might be a visible link in the page for people with JavaScript disabled, and then an AJAX call replaces it with your Flickr images, del.icio.us links or something else.

    In that case, it will be a sort of flickering, and I'd say that it's up to each case to see how bad it is, vs. the gained functionality. Basically, weigh the good against the bad, and consider alternative approaches.

    Jrf,

    I'm glad that you liked the style of this. :-)

    Mats,

    The way I usually toggle content that is initially hidden for user with JavaScript enabled, is that I either add a class to it with that has a stronger specificity than the applied rule used to hide it, or I set it's <code>style</code> property directly. Inline styling in the HTML code should never be necessary.

    Niklas,

    When forced, or in the reloading behavior of some browsers, there might be a delay in reading the file. However, the expires headers should tend to that as far as possible. However, if you experience this behavior where you try to use this approach, use something like <code>document.write</code> to write out the CSS code directly then.

  • Niklas says:

    Yeah, worked better with:

    document.write('');

    Is there any downsid doing it like that except that it doesn't work with xhtml (with correct mime type)?

  • Robert Nyman says:

    Niklas,

    Well, usually <code>document.write</code> is frowned upon since it stalls loading and is an outdated practice. However, in this case, if all else fails, I'd say it's motivated.

  • Adam says:

    Maybe I'm confused here, but wouldn't this approach create sudden "jumping" in browsers that have js enabled?

  • Robert Nyman says:

    Adam,

    No, the way it works is that it will read in the extra CSS file, through JavaScript, before the <code>body</code> has even started loading.

  • But if you do it that way you can't use Prototypes och Scriptacoulus effects since they assume that the element is visible without the style property. Setting a className in "beforeStart" might work though …

    I'll have to try.

  • Robert Nyman says:

    Mats,

    Well, you know what they say about assumptions, right? :-)

    But yes, if that's the case, you need to set the <code>className</code> or something similar before calling the actual effect then.

  • Yes, I have a mental image of Benny Hill and a blackboard … ;) (ass)(u)(me)

    I haven't tried but I just realized that it will only work for Effects … P6Y's Element.hide/show doesn't use callbacks.

    But then again why use P6Y for such simple operations. ;)

  • Robert Nyman says:

    Mats,

    Yep, always use the right tool for the job. :-)

  • Stefan Van Reeth says:

    Cool idea Robert, presented in a clear compact form as ever. Never gave this a thought. But then again, I mostly work on intranet apps and there it isn't priority no 1. Still, it would (or better: will) serve great as a fallback for just in case…

    Greetings, Stefan

  • Robert Nyman says:

    Stefan,

    Yes, it's always good to have an option. :-)

  • Ian Lloyd says:

    Hi Robert,

    Just heard about this technique on Boagworld and came to investigate. I've looked through the comments and search for any mention of screen readers and didn't find anything. Why is this important?

    My understanding about why people opt for the 'display content by default, hide afterwards with JavaScript ' technique is not *just* about providing something for non-JS capable users, but also for people with assistive tech.

    If the page loads and has content hidden with CSS, the screen reader (to use the typical example of assistive technique) does not get to 'see' all the content and therefore cannot then be relayed to the user; using the 'show by default then hide it on page load' technique gets around that problem – the assistive tech gets to 'see' the whole page and can relay that information accordingly, even if it is subsequently hidden on screen.

    Now, I can see what you've done here – you're using JavaScript at what seems like a good point in the page load process to load the additional hide styles to avoid the flash, but I suspect that this will then make any of that content invisible to assistive tech users. I say *suspect* as I'm not able to test that theory out as I type this (at work, no screen reader available on this machine).

    Could you look into that aspect of the technique? If it does present accessibility issues, then a note of warning should be applied.

    Thanks :-)

  • Ian Lloyd says:

    Just to clarify my comment 'Why is this important?' … I meant 'Why is it important [that I was searching for this]' rather than 'Why is this [your technique] important?'. Just re-read it and thought that might not have come across quite as clearly as I hoped :-)

  • Robert Nyman says:

    Ian,

    It's a good point about screen readers. Unfortunately I don't have access to proper screen reader testing opportunities at the moment either, but I had a friend do brief tests for me.

    The result can, most likely, vary from screen reader to screen reader, but a recommended alternative CSS approach to avoid having content not being read is using:

    <code>position: absolute;

    left: -999px;</code>

    instead of

    <code>display: none;</code>

    Then, have your script change the value to:

    <code>position: static;

    left: 0;</code>

    when showing the element.

  • mike foskett says:

    Hi Rob,

    Nice article, here's one more varient to add to the mix:

    <code><script type="text/javascript">/*<![CDATA[*/

    document.documentElement.className="hasJS";

    /*]]>*/</script></code>

    Placed straight after the title element, it adds the class .hasJS to the html element (valid grammatically but cannot have properties).

    So does not interfere with body element at all.

    I sometimes add an extra variable which is set server-side:

    <code>var ajaxOn=true;</code>

    Which may be switched via a content link for accessibility.

    Example: webSemantics

  • Robert Nyman says:

    mike,

    Thanks for sharing!
    Ole was mentioning this above as well, but to my knowledge, it’s not valid to add properties to the HTML element itself.

  • [...] How to hide and show initial content, depending on whether JavaScript support is available [...]

  • dv says:

    <div id="hide-with-script" style="display:none;">

  • [...] Nyman, in his post How to hide and show initial content, depending on whether JavaScript support is available, outlines a technique where you add a <script> element to the <head> of your document [...]

  • [...] Anyways here’s the hack / fix that I found: [...]

  • [...] How to hide and show initial content, depending on whether JavaScript support is available – Robert?… (tags: reference howto tips code) [...]

  • Dallas says:

    The solution that I have found most useful—that is, the solution with the overall performance needed and minimal flicker present—is to have a script tag in the header which does a document.write(…). I’m coding with Rails but this code is easily adapted:

    <%= javascript_tag %(document.write(#{stylesheet_link_tag('javascript').to_json}) %>

    I tried your solution, as I liked the single-line <script src="…"> much better, but with your exact solution and with replacing all of the JavaScript code with the same document.write(…) I still got some page flicker.

    I like the inclusion of a JavaScript-only stylesheet because it lessens the load even more for those non-JS users out there and it just seems a little bit cleaner than adding an extra class to <body>. As far as implementing any sort of JavaScript library functions in the header, it is generally best to include as little JavaScript as possible at the top of your page since it must be completely loaded and run before anything beneath can be loaded.

    Hope this helps a few people.

  • Robert Nyman says:

    Dallas,

    There are a number of downsides to document.write, such as it stalls all other renderering, it won’t work with the proper XHTML MIME type application/text+xhtml etc.

    Without having the actual case at hand, theoretically, you shouldn’t get a flickr. But if that happens, I’d rather see an inline script block at the start of the page which creates a script style through DOM methods rather than using document.write to write a string.

  • [...] How to hide and show initial content, depending on whether JavaScript support is available [...]

  • Jessica says:

    Wonderful, this is just what I was looking for!

    Thank you!

  • Robert Nyman says:

    Jessica,

    You're welcome!

  • My man! Great, elegant solution. I'm definitely throwing this one in the ol' utility belt with attribution to you.

    Cheers,

    Matthew

  • Robert Nyman says:

    Matthew,

    Thank you!

  • Abicus says:

    I am working on 5 sites (various locations) that have the same content, but they all have different headers and footers as they are specific to each location. Instead of creating 5 pages is there a way I can create just the one page and dynamically insert the header and footer? i.e style sheet switcher? like the css zen garden.

  • Bubba Meissa says:

    I prefer to use https://github.com/verbatim/css_browser_selector
    check out:
    https://github.com/verbatim/css_browser_selector/blob/master/css_browser_selector_dev.js

    writes browser, platform, and JS classes to the HTML tag allowing all sorts of CSS granularity. Can even be used with JQuery.

  • Robert Nyman says:

    Bubba,

    Thanks for the tip!

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>