jQuery Show/Hide - CSS display values are affecting my layout

Andy McCluggage picture Andy McCluggage · Nov 16, 2009 · Viewed 12.6k times · Source

jQuery uses the CSS display property under the hood of the simple show() and hide() functions. The following HTML includes three buttons, each wrapped in a <span> tag, and all three <span> tags are placed in a parent <div> container. On page load, the <span> tags are hidden using jQuery hide(), and, at some point later on, they are displayed using the show() function. The HTML is now in the following state with the <span> tag having received the style value display: block;.

<div style="text-align:right; width:100%;">
    <span style="display:block">
        <input type="button" value="Button1" />
    </span>
    <span style="display:block">
        <input type="button" value="Button2" />
    </span>
    <span style="display:block">
        <input type="button" value="Button3" />
    </span>
</div>

In Firefox (3.5) the span elements appear stacked vertically on top of each other, whereas in IE they appear inline. I would have expected the latter in both browsers because I thought that the default layout for span tags was inline.

If I manually change the style from display:block to display: inline;, it looks correct in Firefox. Essentially, when showing an element, jQuery is using a value for display that is not always valid. Adding display: block; is enough to show the element, but not enough to show it with the inline layout I require.

So, to my questions:

  1. Is this a known issue with jQuery? I am using jQuery 1.2.6.
  2. Has anyone experienced this problem before, and how did you get around it?

Answer

Andy McCluggage picture Andy McCluggage · Nov 16, 2009

At first it seemed from the responses that using the show/hide functions would not be possible if I wanted a value of display other than block.

However, I then noticed that, when the <span> tags were in the hidden state, jQuery had added an attribute called oldBlock to each of them. I then realized that this was for temporary storage of the display CSS value when the element is hidden, so that the appropriate value can be reinstated when the elements are shown again.

All I therefore have to do is set the appropriate value for display before I hide the elements.

Initial state:

<div style="text-align:right; width:100%;">
    <span style="display:inline">
        <input type="button" value="Button1" />
    </span>
    ...
</div>

Calling .hide() takes us to this state:

<div style="text-align:right; width:100%;">
    <span style="display:none" oldBlock="inline">
        <input type="button" value="Button1" />
    </span>
    ...
</div>

Calling show() brings us back to this state:

<div style="text-align:right; width:100%;">
    <span style="display:inline">
        <input type="button" value="Button1" />
    </span>
    ...
</div>

The main problem was that I was NOT giving the <span> elements a value for display in my initial state. They would therefore implicitly receive the browser default, which appears to be inline as I expected. However, jQuery will only use the oldBlock attribute if you explicitly set the value for display before you call the hide() function. If there is no oldBlock attribute, the show() function uses the default value of block.