31

I always thought elements that had display:none CSS style returned 0 for height() and width().

But in this example:

HTML

<div id="target" style="display:none;">
a
</div>

CSS

alert($("#target").height());

they don't: http://jsfiddle.net/Gts6A/2/

How come? I've seen 0 come back plenty of times in the past.

Liam
  • 27,717
  • 28
  • 128
  • 190
Foobarbis
  • 735
  • 3
  • 10
  • 12

2 Answers2

55

If an element has an offsetWidth of 0 (jQuery is considering this "hidden"), checked here, then it attempts to figure out what the height should be. It sets the following properties on the element via jQuery.swap() for the duration of the check:

  • position: "absolute"
  • visibility: "hidden"
  • display: "block"

Then it gets the height, via getWidthOrHeight(...) which adds border/padding if necessary via augmentWidthOrHeight(...) depending on the box model, and reverts all of the above properties to their former values.

So basically it's taking the element, showing it out of the flow of the document, getting the height, then hiding it again, all before the UI thread updates so you never see this happen. It's doing this so .height()/.width() works, even on elements that are currently hidden, as long as their parents are visible...so you can run .height()/.width(), without doing the show/hide trick it's doing in your code, it's handled within .height() and .width().

Dan Herbert
  • 99,428
  • 48
  • 189
  • 219
Nick Craver
  • 623,446
  • 136
  • 1,297
  • 1,155
  • how would i handle that in 1.3.2 if the parent element is hidden? – luksak May 30 '11 at 11:49
  • 4
    @elluca - you'd need to temporarily `.show()` the parent when measuring then `.hide()` it back afterwards if you wanted it to remain hidden, the user won't see any changes since the UI thread won't update during this. – Nick Craver May 30 '11 at 12:12
  • 2
    Note that this may give an erroneous value if the parent element in normal flow isn't set as the containing element for the absolute positioning model. – Brent Feb 09 '12 at 19:56
  • 2
    I often find that jQuery's internal swapping stuff isn't accurate all of the time. In some cases (unfortunately I haven't yet exactly nailed down which ones …) it's off by a few pixels. To avoid this I still often go back to the manual procedure of `elem.show();elem.height();elem.hide()` Nick mentioned in his comment above. I find that this is way more reliable, and — as he also mentioned — doesn't have any impact on the UI. – maryisdead Mar 07 '12 at 20:02
  • To add to Nick Craver's and @maryisdead's comment, I had a special case where I had `display: none;` defined in my CSS file and toggled visibility by adding and removing an `active` CSS class that had `display: block;` defined. If you use `elem.hide()`, it will override your CSS definition for `active`. Instead, you can just remove the explicit style added from `elem.show()` by doing something like `elem.css('display', '')`. In doing so, you get the proper height, then allow your CSS to behave normally without being overridden. – Nick Feb 21 '13 at 17:00
5

EDIT

This appears to have been corrected as of jQuery 1.4.4

Example: http://jsfiddle.net/GALc7/1/


I believe this is only true for items whose parent is "display:none"

See this article on the matter http://dev.jquery.com/ticket/125

Also, see this example (save as an .html file) or see ( http://jsfiddle.net/GALc7/ )

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
    <title>Example</title>

    <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>

    <script type="text/javascript">
        $(document).ready(function(){
            alert($("#target").height());
        });
    </script>
</head>

<body>
    <div id="parent" style="display:none;">
        <div id="target" style="height:100px;display:block;">
            a
        </div>
    </div>
</body>
</html>
Brandon Boone
  • 16,281
  • 4
  • 73
  • 100
  • This is what happens to me when I try to get height from a iframe inside a div with display:none attached to it. But is there a solution? – Mr Rebel Jul 16 '14 at 09:43