45

I want to generate html layout with areas (divs, spans) that can be shown/hidden conditionally. These areas are hidden by default.

If I call .hide() method with jquery on document.ready these areas may blink (browsers render partially loaded documents). So I apply "display: none" style in html layout.

I wonder what is the best practice to avoid blinking, because applying "display:none" breaks incapsulation rule - I know what jquery does with hide/show and use it. If jquery's hiding/showing implementation will change one day, I'll get the whole site unworkable.

Thank you in advance

robsch
  • 8,466
  • 8
  • 56
  • 87
Andrew Florko
  • 7,292
  • 9
  • 55
  • 105

12 Answers12

33

@Andrew,

I know the answer has already been accepted, but using display: none; will be a nightmare to users without Javascript.

Using inline Javascript, you can hide an element without it ever blinking. Users without Javascript will still be able to see it.

Consider a few divs that should be hidden when the page loads.

<head>
    <script type="text/javascript" src="jQuery.js"></script>
</head>
<body>
    <div id="hide-me">
        ... some content ...
    </div>
    <script type="text/javascript">
        $("#hide-me").hide();
    </script>

    <div id="hide-me-too">
        ... some content ...
    </div>
    <script type="text/javascript">
        $("#hide-me-too").hide();
    </script>
</body>

The inline Javascript will run as soon as the element is rendered, thus hiding it from the user.

Marko
  • 68,081
  • 26
  • 118
  • 153
  • 14
    That this will work without blinking (in all browsers, for any page) is simply untrue... Different browsers, depending on their exact implementation and the size of the page, may end up "blinking" or even displaying the content for a while. EG sample (1 MB) that displays for a while in Chrome: http://www.architectshack.com/as/BlinkTest.ashx?2 – Tao Jun 20 '12 at 22:05
  • Agreed Tao - this does NOT work in some browsers, including Chrome. – jimasp Jan 06 '14 at 16:06
6

I agree with Boris Guéry, that it is not over-engineering, but rather, a standard best practice. I would go a slightly different way than Boris, by adding a no-js class to the html initially and then removing it with JavaScript.

This way you're not waiting for the document to be ready to hide the content, and without any JavaScript you still see the content. Assuming the user has not JavaScript is more in line with the philosophy of progressive enhancement.

ex:

<html class="no-js">
<body>
<div id="foo"></div>
</body>
</html>

my css :

#foo {
    display: none;
}
html.no-js #foo {
    display: block;
}

and javascript

$(document).ready(
   function()
   {
     $('html').removeClass('no-js');
   }
);

********* OR on a per-case basis***********

ex:

<div class="no-js" id="foo">foobar and stuff</div>

css:

.no-js {
  display:none;
}
#foo {
  display: block;
}
#foo.no-js {
  display: none;
}

js:

$(document).ready(function(){
  // remove the class from any element that has it.
  $('.no-js').removeClass('no-js');
});
robsch
  • 8,466
  • 8
  • 56
  • 87
Ryan Ore
  • 1,179
  • 15
  • 22
  • +1 I really like the idea of this. However using a CMS I can't just edit the html tag. I'm wondering if there is another solution. – Tom May 02 '13 at 02:42
  • It doesn't need to be the html tag, that's just casts the broadest net. Can you add classes to anything? If so then you can do it on a per-case basis, then in the javascript remove the .no-js class from all objects that have it. I'll update my answer with a suggestion. – Ryan Ore May 02 '13 at 14:11
  • to get it working, my script file ended up like this, so the removeClass() fires early, and the show() fires late: $('html').removeClass('no-js'); $(function () { $(window).load(function() { $('#foo').show(); }); }); – jimasp Jan 07 '14 at 10:56
  • I don't get it. How does it work? You are using document-ready like Andrew does it. You are using css classes, he uses hide() of jQuery. Why is your solution better? – robsch May 01 '16 at 12:02
  • CSS will affect the page before it even renders, whereas the jQuery functions don't get called until the document is actually ready. So using hide() means you'll see a flicker of content before it is hidden by the javascript. But using CSS means it won't ever show until you remove that class. – Ryan Ore May 01 '16 at 13:34
  • Thank you for your reply! What happens if JS is not available? I've tried it and it seems to me that the CSS is hiding the div. I don't get why it should be shown? See this [fiddle](https://jsfiddle.net/g83ox7u9/) and comment out the one JS line (which I assume is the same as if JS wouldn't be available) to see that the content then is hidden. – robsch May 02 '16 at 09:39
  • Reasons to hide/show something depends on the situation. If JS is not enabled, you may want to offer a static image, as opposed to some sweet ajaxy gallery. Otherwise they might be seeing an empty div ... Or maybe just a message telling them that they'd be having more fun if they had JavaScript. ... I think the className 'no-js' is confusing, because what it really does is allow you to show alternate content by removing the class as opposed to adding it. Really name things however they make most sense to you. – Ryan Ore May 02 '16 at 15:47
  • I see. I've added now another [answer](http://stackoverflow.com/a/36991047/57091) which is more complex but hopefully solves all issues. – robsch May 02 '16 at 20:27
  • Nice approach! For the per case approach, I don't see why the .no-js {display:none:) is needed as it is already handled by the #foo.no-js {display: none;}. Seems to work for me without it. If somebody could explain what I am missing I would be grateful. – Jeffrey Simon Nov 09 '19 at 01:20
4

I usually set a .js class to my element to set the proper property when javascript is enabled.

I then can set the CSS depending on if javascript is present or not.

ex:

<html class="js">
<body>
<div id="foo"></div>
</body>
</html>

my css :

html.js #foo
{
    display: none;
}

and javascript

$(document).ready(
   function()
   {
     $(html).addClass('js');
   }
);
Boris Guéry
  • 45,611
  • 7
  • 48
  • 85
  • Thank you, but i decided to stop my choice on simple-css & found this mixed (css + javascript) approach overengineered for my tasks. – Andrew Florko May 10 '10 at 07:59
  • 1
    The interest is to keep usability and accessibility for people who doesn't have javascript, if you match your block with its id, it's likely to be hidden for ppl who don't have javascript enabled. You wanted to know best practices, it **IS** a best practice. – Boris Guéry May 10 '10 at 08:35
3

There's absolutely nothing wrong with setting an intial display property of an element, especially if you encapsulate it in a css class.

James H
  • 2,343
  • 3
  • 23
  • 20
3

Why not do just this?:

// Hide HTML element ASAP
$('html').hide();

// DOM-ready function
$(function () {
   // Do stuff with the DOM, if needed
   // ...

   // Show HTML element
   $('html').show();
}

It seems to work fine!

Regards.

Andy
  • 41
  • 2
  • 5
    The problem with this approach is that it causes the whole page to flicker on a page reload. It is most noticeable if you have a dark background. – meesern May 15 '15 at 15:45
3

I struggled with this too, especially in IE, and I found this very helpful: http://robertnyman.com/2008/05/13/how-to-hide-and-show-initial-content-depending-on-whether-javascript-support-is-available/

1

you can apply "display: none" in a CSS class.

Because the order which a browser have to read some HTML code in order for the JavaScript to find the Element. You have to mark the element hidden, as the browser reads your HTML.

How ever you can also insert the HTML in your JavaScript, and you can call hide before it is rendered.

Darkerstar
  • 914
  • 1
  • 8
  • 17
1

This is my suggestion. It utilizes this solution to create a new CSS rule. The main thing: a CSS class that hides some html will be created if JS is available, otherwise not. And this happens before the main content (with the html parts that should be initially hidden) gets processed!

<html>
<head>
    <style>
        /* This class gets overwritten if JS is enabled. If a css file (bootstrap, ...) 
        gets loaded with such a class this would be also overwritten. This solution does 
        not require the class. It is here just to show that it has no effect 
        if JS is activated.*/
        .hidden {
            display: block;
            background: red;
        }
    </style>
    <script>
        // this is copied from the linked stackoverflow reply:
        function setStyle(cssText) {
            var sheet  = document.createElement('style');
            sheet.type = 'text/css';
            /* Optional */
            window.customSheet = sheet;
            (document.head || document.getElementsByTagName('head')[0]).appendChild(sheet);
            return (setStyle = function (cssText, node) {
                if (!node || node.parentNode !== sheet)
                    return sheet.appendChild(document.createTextNode(cssText));
                node.nodeValue = cssText;
                return node;
            })(cssText);
        }

        // And now: This class only gets defined if JS is enabled. Otherwise 
        // it will not be created/overwritten.
        setStyle('.hidden { display: none; }');

        // Attention: Now that the class is defined it could be overwritten 
        // in other CSS declarations (in style tags or with loaded CSS files).
    </script>
</head>
<body>

    <button>Show/Hide</button>

    <div class="">before</div>
    <div class="my-element hidden">
        Content that should be initially hidden if possible.
        You may want to multiply this div by some thousands
        so that you see the effect. With and without JS enabled.
    </div>
    <div class="">after</div>

    <script src="https://code.jquery.com/jquery-2.2.3.min.js"></script>
    <script>
        // Here is some 'normal' JS code. Very likely loaded as a JS file:
        $('button').click(function () {
            $('.my-element').toggleClass('hidden');
            // or setting display directly: 
            //   $('.my-element').toggle() 
            // but well, having class hidden though it is not 
            // hidden makes is not so nice...
        })
    </script>

</body>
</html>

A bit more complicated, but I think this is a proper solution. The advantage is that flickering is prevented and that it works if JS is not enabled. And it doesn't require jQuery.

Community
  • 1
  • 1
robsch
  • 8,466
  • 8
  • 56
  • 87
1

After some time of thinking I've got the idea to the following solution. Compared to my other solution I have reduced it to the essential part (and used this to add a class by JS):

<html>
<head>
    <style>
        /* This could be also part of an css file: */
        .container-with-hidden-elements .element {
            display: none;
        }
    </style>
</head>
<body>
    <div class="container">
        <script>
            document.getElementsByClassName('container')[0]
                    .className += ' container-with-hidden-elements';
        </script>

        <div class="element">Content that should be initially hidden if possible.</div>
    </div>
</body>
</html>

The script tag gets executed immediately and adds a class to a container. Within this container there are some nested elements that get now hidden because the container has got the special class and there is a CSS rule that now has an effect.

Again, this happens before the remaining html gets processed (prevents blinking). And also, if JS is disabled, all the elements are visibly by default - what may be called Progressive enhancement.

Not sure if this works in every browser. But IMO it would be simple and neat solution.

Community
  • 1
  • 1
robsch
  • 8,466
  • 8
  • 56
  • 87
0

I would always use Modernizr.js http://modernizr.com/ to handle this.

With Mondernizr a class 'js' or 'no-js' is added to the HTML tag of your page.

From here you can hide your elements only if the html tag has the js class.

Modernizr is great for so many other applications and worth reading up on if you've not used it before: http://modernizr.com/docs/

Jimbo Jones
  • 552
  • 6
  • 28
0

What I always do is create an empty div. And if some data inside that component needs to be shown, I asynchronously load data (i.e. html) into it using $.ajax().

No need for an extra lib.

Coen Damen
  • 1,651
  • 4
  • 25
  • 47
0

There are many answers, you can use the show() method and code the condition to show or hide. Here is the sample code show_hide when rendering is complete

  <div id="banner-message">
  <p id="hello">Hello World!!!!!</p>
  <input id="statusconf" value="" type="checkbox">Show hello world text when i click this check box
  <button>Change color</button>
</div>

    // find elements
var banner = $("#banner-message")
var button = $("button")

// handle click and add class
button.on("click", function(){
  banner.addClass("alt")
})

//Set this up as part of document ready if you wish
//$(document).ready(function(e) {

    $("#statusconf").show(function(e) {
            if ($("#statusconf").is(':checked') === false) {
                $('#hello').hide();
            } else {
        $("#hello").show();
      }
  });

    $("#statusconf").on("click", function(e) {
    if ($("#statusconf").is(':checked') === false) {
                $('#hello').hide();
            } else {
        $("#hello").show();
      }
  });

//});
webjockey
  • 1,159
  • 2
  • 15
  • 24