views:

1240

answers:

4

JQuery uses the Css Display value 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 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?
+1  A: 

Instead of using show/hide use addClass/removeClass and have the style you wish to be applied set up using the class.

.hidden
{
    display: none;
}

.inline
{
    display: inline;
}

.block
{
    display: block;
}

Sample usage:

$('.menuitem').hover(
      function() {
           $(this).parent()
                  .find('span')
                  .removeClass('inline block')
                  .addClass('hidden');
           $(this).addClass('inline');
      },
      function() {
           $(this).addClass('inline');
      }
});
tvanfosson
It does seem that if I want the level of control such that I can choose the value of the Display style property, I will not be able to use the show/hide functions. This is a shame but to be expected. Thanks for this suggestion.
Andy McCluggage
the problem with this approach is it is basically a hack. your code knowing too much about your css. yes it can definitely work sometimes but i'm trying to avoid this as much as possible
Simon_Weaver
+1  A: 

I haven't had this specific problem, but for more control use .toggleClass()

ScottE
This would be a great solution to replace toggle(), but a more direct replacement for show/hide would be add/remove as the semantics are directly equivalent.
tvanfosson
This is fine, but show() and hide() involve some animation, and are interchangeable with stuff like slideDown and slideUp, so if he wants to keep the animation, just changing the class wouldn't do that.
Nathan Long
I'm not sure if it is possible at all to animate inline elements.
Patonza
A: 

I haven't had this problem, but if you need to, you can explicitly set css properties like this:

$(this).show('fast').css("display","inline");
Nathan Long
+2  A: 

Thanks everyone for your suggestions. 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 realised 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 eleements are shown again.

All I therefore have to do it ensure I 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 implicitally receive the Browser default, which appears to be inline as I expected. However JQuery will only use the oldBlock attribute if you explicitally 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.

Thanks again for your suggestions.

Andy McCluggage
thanks, this helped fix a weird bug in IE 6/7
Steven Sproat