Bug Tracker

Ticket #2503 (closed bug: duplicate)

Opened 7 years ago

Last modified 6 years ago

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:
Blocking: Blocked by:

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.

Change History

comment:1 Changed 7 years ago by apramanik

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

comment:2 Changed 7 years ago by apramanik

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.

comment:3 Changed 7 years ago by apramanik

The changes are all near the bottom of the code.

comment:5 Changed 6 years ago by dmethvin

  • Status changed from new to closed
  • Resolution set to duplicate

This is a dup of #2185.

Note: See TracTickets for help on using tickets.