How to write CSS fallbacks for when Javascript is disabled
Asked Answered
F

4

5

I'm using jQuery in the examples below, but my question applies more generally to any situation where javascript is used to display something that would be missed if javascript wasn't enabled.

Let's say I want to fade in some text when the page loads:

.fade-in { opacity:0; }

<div class="fade-in">FOOBAR</div>

$('.fade-in').fadeIn();

But what if the client doesn't have javascript enabled?

I don't want the text to remain invisible, so maybe I set the CSS to the end state as a fallback, and then UN-set it with javascript prior to the animation. This way, users without javascript just see normal text (without a fadeIn), and users with JS see the fade.

.fade-in { opacity:1; }

<div class="fade-in">FOOBAR</div>

$('.fade-in').css('opacity', 0);
$('.fade-in').fadeIn();

This works, but in most cases it will result in an unpleasant "flicker" between when the CSS display property is set and when the javascript unsets it. In the above example, a user with javascript working normally would see the "FOOBAR" appear for a split second, then vanish, then fade in.

Is there a best practice for this which doesn't result in the flicker OR sacrificing no-JS users?

Please do not fixate on the trivial example above. That is just to demonstrate the concept. I'm looking for a broader strategy for handling these cases. Also, I don't want to debate the merits of progressive enhancement or whether it is or isn't necessary to support the no-JS users. That's a question for another thread(s).

Update: I know tools like Modernizr can be used to add .no-js classes, etc but I'd prefer a solution that does not rely on these libraries.

Featherstone answered 5/3, 2014 at 16:11 Comment(5)
Are you running the function to fade the values with a ready event handler? That should be fast enough to avoid the flicker. Really the way you should be thinking about it is to make a page functional without Javascript first, then use Javascript to enhance it.Pentastich
@DissidentRage I am usually running the animations from inside $(document).ready(...). In my experience, the CSS often appears momentarily before the code inside ready() has a chance to override it.Featherstone
Odd. Unless .ready() isn't using DOMContentLoaded it should outrun loading the CSS.Pentastich
@DissidentRage It's been a while since I read up on this, but I think you're thinking of $(document).load() which fires sooner.Featherstone
Not according to this: #8396907 It seems jQuery doesn't actually use DOMContentLoaded in either and instead uses document.oncontentready which is slower than DOMContentLoaded but faster than window.onload.Pentastich
S
10

If the user doesn't have JS enabled, create a stylesheet for him:

<head>
scripts
<noscript><link href="no-js.css" /> </noscript>
</head>
Sinkage answered 5/3, 2014 at 16:13 Comment(2)
Right! The trusty no-js stylesheet. I was picturing a solution that used the same stylesheet, but not for any particular reason. This is probably the best way.Featherstone
Just add a class (no-js) to the body in the head inside the <noscript> tags and then you can use a single stylesheet. .no-js selector etc.Subito
E
3

Use <noscript></noscript> tags

Ezraezri answered 5/3, 2014 at 16:13 Comment(0)
F
0

I wonder, would something like this work?

<body>

<noscript>
<div class="no-js">
</noscript>

...

<noscript>
</div>
</noscript>

</body>

The idea is to keep all the CSS in one stylesheet by conditionally wrapping the elements in .no-js class without requiring Modernizr.

Featherstone answered 5/3, 2014 at 16:27 Comment(0)
M
0

Here is my best bet for you: use a no-js and a js classes on your html element:

<html class="no-js">
<head>
    <title>...</title>
    <!-- Change "no-js" class to "js" in the html element -->
    <!-- This must appear high in your page to avoid FOUC effect -->
    <script>(function(H){H.className=H.className.replace(/\bno-js\b/,'js')})(document.documentElement)</script>
</head>
<body>
    ...
</body>
</html>

This way, your CSS could look like this:

/* The item first appears with opacity=1, then disappears when the no-js class is removed */
.no-js .fade-in { opacity: 1; }
.fade-in { opacity: 0; }

This is almost what tools like Modernizr are doing but very simplified here :)

Credits goes to Paul Irish: http://www.paulirish.com/2009/avoiding-the-fouc-v3/

Maurita answered 25/8, 2014 at 11:42 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.