Is Showing and Hiding Web Content Using jQuery Bad?

Don't Shoot the Messenger

OK, first the disclaimers: I am not saying there is no place for showing and hiding content using JavaScript/jQuery. I am merely saying that doing so can be causing you more problems than necessary. And yes, I do generally follow best-practices by having content display-by-default and using script to cause it to not be shown - thus allowing the content to be seen by those tinfoil-hat-wearing conspiracy theorists who disable JavaScript in their browsers - and who, incidentally, seem to make up a large percentage of my followers ;-).

jQuery makes it so easy, it is really tempting to just slap a .hide() or .show() on a selector and mission accomplished, right? Or even more tempting, .slideDown() or .slideUp(), with their animation? OK, what will happen to your interface if the browser is resized smaller after you show some popup content? Perhaps resized below one of your CSS breakpoints, maybe down to a smartphone size? Go ahead, try it out. I'll wait right here while you do.

The Scenario

Suppose you have some content that you wish to have shown or hidden whenever the user clicks on another element:

<h2>Header One</h2>
<div class="content">Lorem ipsum dolor sit amet. . . </div>

Further, suppose you want to make it easier on mobile users and just have the content always visible. So you set it up with a media query in your CSS to hide the content on larger screens:

@media screen and (min-width: 40em) {
    .content {
        display: none;
    }
}

The Problem

The problem is that all of the jQuery methods to show this content (.hide(), .slideUp(), .fadeOut(), etc) all add an inline style on the element so that whether the browser size is below or above 640 pixels (under normal browser settings) the media query no longer governs display - the content div will be hidden even on a small screen.

You can view a jsFiddle here. Try it - resize the browser to see the media query show and hide the content divs. Then, with the browser full-size, click on a header to show/hide its related content. Then resize the browser once more to see the change in the behavior.

So that leaves you writing MORE JavaScript to detect when the browser is resized and determining whether it is above or below your CSS breakpoint and re-showing the content div, or perhaps (just as bad) you are adding another media query for sizes < 40em and forcing the display with an !important flag on the display for the div. Horrors!!

The Solution

As with many programming dilemmas, the solution becomes easier to see with a more specific rephrasing of the problem (that is the principle underlying rubber duck debugging, but that is a whole different post). The display of the content div should be governed by whether the screen is small OR whether the user has clicked on the heading. And the hiding of the content div should be governed by whether the screen is large AND the user has not clicked on the heading.

This means that you cannot show or hide the content div upon a click. Instead you have to toggle some sort of switch that will control only half of the decision of whether to show or hide the content. In CSS, this type of switch is typically a class. Use the click to toggle a class on the content div and use the CSS to hide the element only if the screen is large AND the class is absent. The JavaScript:

$('h2').click(function() {
    $(this).next().toggleClass('open');
});

and the CSS:

@media screen and (min-width: 40em) {
    .content { display: none; }
    .content.open { display: block; }
}

Check out a working jsFiddle here, which also includes some animation, courtesy of CSS. Resize and click away to your heart's content; the behavior will be as specified regardless of the screen size.

May all your code be groovy!

Author Avatar
Share this: