views:

1484

answers:

3

I'm trying to get an element to animate to its "natural" height - i.e. the height it would be if it had height: auto;.

I've come up with this:

var currentHeight = $this.height();
$this.css('height', 'auto');
var height = $this.height();
$this.css('height', currentHeight + 'px');

$this.animate({'height': height});

Is there a better way to do this? It feels like a bit of a hack.

Edit: Here's a complete script to play with for anyone that wants to test.

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"&gt; 
<html lang="en"> 
    <head>
     <title>jQuery</title>
     <style type="text/css">
      p { overflow: hidden; background-color: red; border: 1px solid black; }
      .closed { height: 1px; }
     </style>
     <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.js"&gt;&lt;/script&gt;
     <script type="text/javascript">
     $().ready(function()
     {
      $('div').click(function()
      {
       $('p').each(function()
       {
        var $this = $(this);

        if ($this.hasClass('closed'))
        {
         var currentHeight = $this.height();
         $this.css('height', 'auto');
         var height = $this.height();
         $this.css('height', currentHeight + 'px');

         $this.animate({'height': height});
        }
        else
        {
         $this.animate({'height': 1});
        }

        $this.toggleClass('closed');
       });
      });
     });
     </script>
    </head>

    <body>

     <div>Click Me</div>
     <p>Hello - I started open</p>
     <p class="closed">Hello - I started closed</p>

    </body>
</html>
+2  A: 

I could suggest an equally-hackish solution...Clone the element, position it out of view, and get its height...then delete it and animate your original.

That aside, you could also use $.slideUp() and $.slideDown():

$this.hasClass('closed') ? $(this).slideDown() : $(this).slideUp() ;

If you need to keep a 1px line, you can apply that with a parent element:

<div style='border-top:1px solid #333333'>
  <div class='toggleMe'>Hello World</div>
</div>

And apply the slidingUp/Down on the .toggleMe div.

Jonathan Sampson
Sounds like it would work but I'm not sure it would be an improvement :) What I have works but I'm new to jQuery so I'm thinking there must be a non-hacky way
Greg
Any reason you decided not to go with $.slideUp() and $.slideDown()?
Jonathan Sampson
I need it to stop at 1px heigh and I don't think that's possible with those functions (could be wrong though)
Greg
Also it needs to be able to start in a closed or open state, before jQuery starts running, if that matters
Greg
Can the 1px height be simulated by an element around the toggled-element? <div style="border-top:1px"><div class="toggle"></div></div>?
Jonathan Sampson
Hmmm that's a possibility...
Greg
I've gone with adding a wrapper div - simple, works well and lets me use slide instead of animate... thanks
Greg
There is a naturalHeight attribute for images in firefox, this article describes an internet explorer workaround: http://arunprasad.wordpress.com/2008/08/26/naturalwidth-and-naturalheight-for-image-element-in-internet-explorer/
ko-dos
A: 
$('div').click(function() { 
    if($('p').is(':hidden')) {
       $('p').slideUp();
    } else {
       $('p').slideDown(function() { $('p').css('height','1px'); });
    }
}

That should set the height of the p tags to be 1px once they've finished sliding.

Steerpike
That would set the height of every p-tag to 1px.
Jonathan Sampson
$(this).css('height','1px'); should be fine then.
Steerpike
You're applying it on the callback of the slideDown() method, which means as soon as it's visible, it's going to be hidden again. Did you mean to set it for the slideup instead?
Jonathan Sampson
Hmm, I think I got my reveal/hide functions mixed up, yeah. Either way getting show/hide functionality to work should be a lot simpler than checking for heights and such.
Steerpike
+1  A: 

I permit myself to answer this thread, even if it's been answered a long time ago, cuz it just helped me.

In fact, i don't understand the first answer : why opening a half-closed element to get its height, and then closing it again ?

At the beginning, you hide the element so that just a part of it appears, right ? The best way (i believe) to do this is onready, with javascript. So, when you hide the element onready, just save the orig height in a var, so you don't have to hide(onready)-show-save height-hide to be able to toggle the elements visibility.

Look at what i did, it works perfectly :

$(document).ready(function(){
var origHeight = $("#foo").css('height');
$("#foo").css({"height" : "80px"});
$("#foo .toggle").bind("click", function(event){ toggleFoo(event, lastSearchesMidHeight); });
});

Here, when you call your toggle function, you know what is your original element height without wanking around.

I wrote it fast, hoping it could help someone in the future.

Pioul