Skip to main content

Bug Tracker

Side navigation

#2503 closed bug (duplicate)

Opened March 13, 2008 06:33PM UTC

Closed February 18, 2009 03:38AM UTC

jQuery.fx.update does not account for inline-block elements.

Reported by: apramanik Owned by:
Priority: minor Milestone:
Component: effects Version: 1.2.3
Keywords: Cc:
Blocked by: Blocking:
Description

I was getting popping in my animations for inline-block

(or -moz-inline-box) spans due to them being changed to blocks in jQuery.fx.prototype. I fixed it by making the following changes:

jQuery.fx.prototype = {

        // Simple function for setting a style value
        update: function(){
                if ( this.options.step )
                        this.options.step.apply( this.elem, [ this.now, this ] );

                (jQuery.fx.step[this.prop] || jQuery.fx.step._default)( this );

                // Set display property to block for height/width animations
                if ( this.prop == "height" || this.prop == "width" )
                        this.elem.style.display = "block";
        },

to

jQuery.fx.prototype = {

        // Simple function for setting a style value
        update: function(){
                if ( this.options.step )
                        this.options.step.apply( this.elem, [ this.now, this ] );

                (jQuery.fx.step[this.prop] || jQuery.fx.step._default)( this );


                var comp_display = jQuery( this.elem ).css( 'display' );


                // Set display property to block for height/width animations, if it isn't a
                // block value already.
                if ( ( this.prop == "height" || this.prop == "width" )
                                 && comp_display != "inline-block"
                                 && comp_display != "-moz-inline-box"
                                 && comp_display != "block" )
                        this.elem.style.display = "block";
        }, 

As mentioned by John Resig, this solution would be slow because it is computing the display property on every frame of animation.

Attachments (0)
Change History (4)

Changed March 13, 2008 11:11PM UTC by apramanik comment:1

Change comp_display to this.options.display. This is computed on effect creation.

Changed March 13, 2008 11:56PM UTC by apramanik comment:2

You can't specify what display to transition to on a 'show'. So I made the following changes to allow specification of a display attribute ( e.g. $j( 'a' ).animate( { height: 'show', display : 'inline-block' } ) ). If it isn't specified then it defaults to 'block':

	// Simple function for setting a style value
	update: function(){
		if ( this.options.step )
			this.options.step.apply( this.elem, [ this.now, this ] );

		(jQuery.fx.step[this.prop] || jQuery.fx.step._default)( this );

		// Set display property to block for height/width animations, if it isn't a
		// block value already.
		if ( ( this.prop == "height" || this.prop == "width" ) 
				 && this.options.display != "inline-block" 
				 && this.options.display != "-moz-inline-box" 
				 && this.options.display != "block" )
		{
			this.elem.style.display = this.options.to_display ? this.options.to_display : "block";
		}
	},

...

	step: function(gotoEnd){
		var t = (new Date()).getTime();

		if ( gotoEnd || t > this.options.duration + this.startTime ) {
			this.now = this.end;
			this.pos = this.state = 1;
			this.update();

			this.options.curAnim[ this.prop ] = true;

			var done = true;
			for ( var i in this.options.curAnim )
				if ( this.options.curAnim[i] !== true )
					done = false;

			if ( done ) {
				if ( this.options.display != null ) {
					// Reset the overflow
					this.elem.style.overflow = this.options.overflow;
				
					// Reset the display
					this.elem.style.display = this.options.display;
					if ( jQuery.css(this.elem, "display") == "none" )
						this.elem.style.display = this.options.to_display ? this.options.to_display : "block";
				}

...

	animate: function( prop, speed, easing, callback ) {
		var optall = jQuery.speed(speed, easing, callback);

		return this[ optall.queue === false ? "each" : "queue" ](function(){
			if ( this.nodeType != 1)
				return false;

			var opt = jQuery.extend({}, optall);
			var hidden = jQuery(this).is(":hidden"), self = this;
			
			for ( var p in prop ) {
				if ( prop[p] == "hide" && hidden || prop[p] == "show" && !hidden )
					return jQuery.isFunction(opt.complete) && opt.complete.apply(this);

				if ( p == "height" || p == "width" ) {
					// Store display property
					opt.display = jQuery.css(this, "display");
					opt.to_display = prop['display'];

					// Make sure that nothing sneaks out
					opt.overflow = this.style.overflow;
				}
			}

That's the best I could think of so far. I'm not fond of the conditionals and would rather just default this.options.to_display to 'block', but I'm not sure where the best place to put that would be.

Changed March 13, 2008 11:56PM UTC by apramanik comment:3

The changes are all near the bottom of the code.

Changed February 18, 2009 03:38AM UTC by dmethvin comment:4

resolution: → duplicate
status: newclosed

This is a dup of #2185.