views:

1766

answers:

6

I tried to slide in and out a DIV with the toggle function of jQuery but the result is always jumpy at the start and/or end of the animation. Here's the js code that I use:

$(document).ready(function(){
    $('#link1').click(
        function() {
            $('#note_1').parent().slideToggle(5000);
        }
);

And the HTML:

<div class="notice">
    <p>Here's some text. And more text. <span id="link1">Test1</span></p>
    <div class="wrapper">
        <div id="note_1">
            <p>Some content</p>
            <p>More blalba</p>
        </div>
    </div>
</div>

You can also see the complete example here: jQuery Slide test

I usually use Mootools and I can do this slide without any problems with it. But I'm starting a new project in Django and most app in Django use jQuery. So for that and after reading this jQuery vs Mootools I decided that will be a good occasion to start using jQuery. So my first need was to slide this DIV. And it didn't work properly.

I did more search and I found that's an old bug in jQuery with margin and padding applied to the DIV. The solution is to wrap the DIV in another DIV. It didn't fix the thing in my case.

Searching further I found this post Slidedown animation jumprevisited. It fix a jump at one end but not at the other (Test2 in jQuery Slide test).

On Stack Overflow I found this jQuery IE jerky slide animation. In the comments I saw that the problem is with the P tag inside the DIV. If I replace the P tags with DIV tags that fix the problem but that's not a proper solution.

Lastly I found this Weird jQuery behavior slide. Reading it I understood that the problem resolved by switching from P tag to DIV was with the margins of the P (not present in the DIV) and the collapsing of margins between elements. So if I switch the margins to paddings it fix the problem. But I loose the collapsing behavior of margins, collapsing that I want.

Honestly I can say that my first experience with jQuery is not really good. If I want to use one of the simplest effect in jQuery I have to not use the proper function (slideToggle) but instead use some hand made code AND wrap the DIV in another DIV AND switch margins to paddings, messing my layout.

Did I miss a simpler solution ?

As krdluzni suggest, I tried to write as custom script with the animate method. Here's my code:

var $div = $('#note_2').parent();
var height = $div.height();

$('#link2').click(
    function () {
        if ( $div.height() > 0 ) {
            $div.animate({ height: 0 }, { duration: 5000 }).css('overflow', 'hidden');
        } else {
            $div.animate({ height : height }, { duration: 5000 });
        }

        return false;
});

But that doesn't work either because jQuery always set the overflow to visible at the end of the animation. So the DIV is reapearing at the end of the animation but overlaid on the rest of the content.

I tried also with UI.Slide (and Scale and Size). It works but the content below the DIV doesn't move with the animation. It only jump at the end/start of the animation to fill the gap. I don't want that.

UPDATE:

One part of the solution is to set the height of the container DIV dynamically before anything. This solve one jumping. But not the one cause by collapsing margin. Here's the code:

var parent_div = $("#note_1").parent();
parent_div.css("height", parent_div.height()+"px");
parent_div.hide();

SECOND UPDATE:

You can see the bug on the jQuery own site at this page (Example B): Tutorials:Live Examples of jQuery

THIRD UPDATE:

Tried with jQuery 1.4, no more chance :-(

+1  A: 

Try removing all CSS margins from all the elements. Usually jerky animation comes from margins not being taken into account by the animation framework.

Adam Luter
As I write it, it fix the problem if I remove the margins from the P tag and replace it by paddings. But that's not a proper solution for me because it's messing my layout because I loose the collapsing behavior of the margins.
Etienne
He has already identified what's causing it, but he stated he wants the margins to be margins. Removing them is against his spec.
krdluzni
Etienne, you will need to first remove the margins around the element being animated with a style() command, then animate it, then. You would still get jerky behaviour at the top and bottom elements and would have to handle these edge cases specifically.
Adam Luter
Sorry "then animate it, then" should read: then animate it, then when reappearing you will need to restore the margins after the reappear animation has finished.
Adam Luter
Adam that could be a solution. But that doesn't look special edge case to me to have P tag with margins inside a DIV that I want to slide. I think the root of the problem is that jQuery set the DIV to display:none at the end of the animation. That remove the DIV from the display with all its margins. See my comment to krdluzni.
Etienne
In that case, I think you can use the animate method and specify you want the height to be set to 0, rather than 'hide' -- I have not personally used the jquery animations though.
Adam Luter
+1  A: 

You could write a custom animation using the animate method. This will give you absolute control over all details.

krdluzni
This would be worth a try. I never use the built in Events unless its a trivial show/hide.
Mike
It's what I did by implementing the solution shown in "Slidedown animation jumprevisited". Maybe I have to tailor it to deal with the collapsing of the margins. I will try that. JQuery was suppose to be simple and the first simple thing I want to do start to be really complicated. Finally I probably have to reimplement the Mootools solution to slide (no display:none so the DIV stay in place with its margins) in jQuery.
Etienne
I tried in many ways with the animation method and the problem is always the same. If I use hide/show, this set display to none/block. But with display: none, I lost margins of the DIV. If I use only animate with a height of 0. At the end of the animation jQuery set the overflow to visible, overlaying the content the DIV that is suppose to be hidden.Any way I try, there's always a road block :(
Etienne
jQuery shouldn't be changing the overflow after a custom animation unless you tell it to...
krdluzni
A: 

You might try adding a doctype if you don't have one, it worked for me on IE8 after I found the suggestion here on SO: jQuery slideToggle jumps around. He suggests a strict DTD but I just used the doctype that google.com uses: <!doctype html> and it fixed my problem.

Andrew
Thanks for the answer. I already have a DOCTYPE (XHTML-Transitional, not strict). But you can see the bug on Jquery own site with in a page that have a DOCTYPE of XHTML-strict here (Example B):http://docs.jquery.com/Tutorials:Live_Examples_of_jQuery
Etienne
Tried IE8 and Chrome3. I see jumpiness in both and understand what you mean. Looks like an issue with jQuery.
Andrew
A: 

You just have to modify the up, down effects in effects.js to have them take into account margins or paddings that may exist and then adjust what they perceive to be the total size of the element to accommodate those values...something along these lines....

Effect.BlindDown = function(element) { element = $(element); var elementDimensions = element.getDimensions();

//below* var paddingtop = parseInt(element.getStyle('padding-top')); var paddingbottom = parseInt(element.getStyle('padding-bottom')); var totalPadding = paddingtop + paddingbottom;

if(totalPadding > 0) { elementDimensions.height = (elementDimensions.height - totalPadding); } //above*

return new Effect.Scale(element, 100, Object.extend({ scaleContent: false, scaleX: false, scaleFrom: 0, scaleMode: {originalHeight: elementDimensions.height, originalWidth: elementDimensions.width}, restoreAfterFinish: true, afterSetup: function(effect) { effect.element.makeClipping().setStyle({height: '0px'}).show(); }, afterFinishInternal: function(effect) { effect.element.undoClipping(); } }, arguments[1] || { })); };

brycer
Thanks for your answer. I will try this when I get more time. But I can say that I don't agree with the word *just* in "You just have to...". The code that you proposed is far from trivial for a function (slide) that should just works. For me this solution is patching a defect in the jQuery slide funtion. I will propably add a bug to their tracker.
Etienne
+1  A: 

The solution is that sliding div must has width not auto, not in %, but only in px. And We have great result!!! Problem is in inline elemets that are in sliding div. Example: look here

but if they have width in px the height will be identical. Try it. Wait for comments

Jenechka
I tried to set the width in px of the sliding DIV without any success. I tried also to set the width in px for every elements in the sliding DIV and that change also nothing. I always have the jumpy behavior. I'm sure the problem is with the collapsing of margins. I will try jQuery 1.4 and see if the problem persist...
Etienne
Tried with jQuery 1.4, no more chance :-(
Etienne
A: 

I have exactly the same issue with jquery slide, jumpy and looks bad : (

I have no margins at all as I usually code sites to avoid them so I don't need to put ie6 margin fixes in. So margins is not the issue.

I do have divs with a % width, I have no option for the layout I am using so changing to px is not a solution.

I have used a couple of jquery effects in the past with limited success, always ends up with issues or conflicts of some kind.

Fortunately only for visual effects so I can live with out them but its a bit sad to spend so much time on something only to find it doesn't work properly.

PeteJ