Question

So this might be really simple, but I haven't been able to find any examples to learn off of yet, so please bear with me. ;)

Here's basically what I want to do:

<div>Lots of content! Lots of content! Lots of content! ...</div>

.... 

$("div").html("Itsy-bitsy bit of content!");

I want to smoothly animate between the dimensions of the div with lots of content to the dimensions of the div with very little when the new content is injected.

Thoughts?

Was it helpful?

Solution

Try this jQuery plugin:

// Animates the dimensional changes resulting from altering element contents
// Usage examples: 
//    $("#myElement").showHtml("new HTML contents");
//    $("div").showHtml("new HTML contents", 400);
//    $(".className").showHtml("new HTML contents", 400, 
//                    function() {/* on completion */});
(function($)
{
   $.fn.showHtml = function(html, speed, callback)
   {
      return this.each(function()
      {
         // The element to be modified
         var el = $(this);

         // Preserve the original values of width and height - they'll need 
         // to be modified during the animation, but can be restored once
         // the animation has completed.
         var finish = {width: this.style.width, height: this.style.height};

         // The original width and height represented as pixel values.
         // These will only be the same as `finish` if this element had its
         // dimensions specified explicitly and in pixels. Of course, if that 
         // was done then this entire routine is pointless, as the dimensions 
         // won't change when the content is changed.
         var cur = {width: el.width()+'px', height: el.height()+'px'};

         // Modify the element's contents. Element will resize.
         el.html(html);

         // Capture the final dimensions of the element 
         // (with initial style settings still in effect)
         var next = {width: el.width()+'px', height: el.height()+'px'};

         el .css(cur) // restore initial dimensions
            .animate(next, speed, function()  // animate to final dimensions
            {
               el.css(finish); // restore initial style settings
               if ( $.isFunction(callback) ) callback();
            });
      });
   };


})(jQuery);

Commenter RonLugge points out that this can cause problems if you call it twice on the same element(s), where the first animation hasn't finished before the second begins. This is because the second animation will take the current (mid-animation) sizes as the desired "ending" values, and proceed to fix them as the final values (effectively stopping the animation in its tracks rather than animating toward the "natural" size)...

The easiest way to resolve this is to call stop() before calling showHtml(), and passing true for the second (jumpToEnd) parameter:

$(selector).showHtml("new HTML contents")
           .stop(true, true)
           .showHtml("even newer contents");

This will cause the first animation to complete immediately (if it is still running), before beginning a new one.

OTHER TIPS

You can use the animate method.

$("div").animate({width:"200px"},400);

maybe something like this?

$(".testLink").click(function(event) {
    event.preventDefault();
    $(".testDiv").hide(400,function(event) {
        $(this).html("Itsy-bitsy bit of content!").show(400);
    });
});

Close to what I think you wanted, also try slideIn/slideOut or look at the UI/Effects plugin.

Here is how I fixed this, I hope this will be usefull ! The animation is 100% smooth :)

HTML:

<div id="div-1"><div id="div-2">Some content here</div></div>

Javascript:

// cache selectors for better performance
var container = $('#div-1'),
    wrapper = $('#div-2');

// temporarily fix the outer div's width
container.css({width: wrapper.width()});
// fade opacity of inner div - use opacity because we cannot get the width or height of an element with display set to none
wrapper.fadeTo('slow', 0, function(){
    // change the div content
    container.html("<div id=\"2\" style=\"display: none;\">new content (with a new width)</div>");
    // give the outer div the same width as the inner div with a smooth animation
    container.animate({width: wrapper.width()}, function(){
        // show the inner div
        wrapper.fadeTo('slow', 1);
    });
});

There might be a shorter version of my code, but I just kept it like this.

This does the job for me. You can also add a width to the temp div.

$('div#to-transition').wrap( '<div id="tmp"></div>' );
$('div#tmp').css( { height: $('div#to-transition').outerHeight() + 'px' } );
$('div#to-transition').fadeOut('fast', function() {
  $(this).html(new_html);
  $('div#tmp').animate( { height: $(this).outerHeight() + 'px' }, 'fast' );
  $(this).fadeIn('fast', function() {
    $(this).unwrap();
  });
});

Hello meyahoocoma4c5ki0pprxr19sxhajsogo6jgks5dt.

You could wrap the 'content div' with an 'outer div' which is set to an absolute width value. Inject the new content with a "hide()" or "animate({width})" method, shown in the other answers. This way, the page doesn't reflow in between because the wrapper div holds a steady width.

You can smooth out the jQuery animation using dequeue. Test for presence of class (set upon hover and removed on mouseOut animate callback) before staring new animation. When new animation does start, dequeue.

Here's a quick demo.

var space = ($(window).width() - 100);
$('.column').width(space/4);

$(".column").click(function(){
    if (!$(this).hasClass('animated')) {
        $('.column').not($(this).parent()).dequeue().stop().animate({width: 'toggle', opacity: '0.75'}, 1750,'linear', function () {});
    }

  $(this).addClass('animated');
    $('.column').not($(this).parent()).dequeue().stop().animate({width: 'toggle', opacity: '0.75'}, 1750,'linear', function () {
          $(this).removeClass('animated').dequeue();

      });
    $(this).dequeue().stop().animate({
        width:(space/4)
    }, 1400,'linear',function(){
      $(this).html('AGAIN');
    });
});

The demo is setup as 5 full-height columns, clicking any of the columns 2 thru 5 will animate toggle width of the other 3 and move the clicked element to the far left.

enter image description here

enter image description here

To piggy-back on the jquery plugin solution (too low of reputation to add this as a comment) jQuery.html() will remove any event handlers on the appended html. Changing:

// Modify the element's contents. Element will resize.
el.html(html);

to

// Modify the element's contents. Element will resize.
el.append(html);

will retain the event handlers of the "html" elements

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top