Skip to content

Commit 692f9d4

Browse files
authored
CSS: Avoid unit-conversion interference from CSS upper bounds
Fixes gh-2144 Closes gh-3745
1 parent b1b949d commit 692f9d4

File tree

3 files changed

+37
-18
lines changed

3 files changed

+37
-18
lines changed

src/css/adjustCSS.js

Lines changed: 19 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,7 @@ define( [
66
"use strict";
77

88
function adjustCSS( elem, prop, valueParts, tween ) {
9-
var adjusted,
10-
scale = 1,
9+
var adjusted, scale,
1110
maxIterations = 20,
1211
currentValue = tween ?
1312
function() {
@@ -25,30 +24,33 @@ function adjustCSS( elem, prop, valueParts, tween ) {
2524

2625
if ( initialInUnit && initialInUnit[ 3 ] !== unit ) {
2726

27+
// Support: Firefox <=54
28+
// Halve the iteration target value to prevent interference from CSS upper bounds (gh-2144)
29+
initial = initial / 2;
30+
2831
// Trust units reported by jQuery.css
2932
unit = unit || initialInUnit[ 3 ];
3033

31-
// Make sure we update the tween properties later on
32-
valueParts = valueParts || [];
33-
3434
// Iteratively approximate from a nonzero starting point
3535
initialInUnit = +initial || 1;
3636

37-
do {
38-
39-
// If previous iteration zeroed out, double until we get *something*.
40-
// Use string for doubling so we don't accidentally see scale as unchanged below
41-
scale = scale || ".5";
37+
while ( maxIterations-- ) {
4238

43-
// Adjust and apply
44-
initialInUnit = initialInUnit / scale;
39+
// Evaluate and update our best guess (doubling guesses that zero out).
40+
// Finish if the scale equals or crosses 1 (making the old*new product non-positive).
4541
jQuery.style( elem, prop, initialInUnit + unit );
42+
if ( ( 1 - scale ) * ( 1 - ( scale = currentValue() / initial || 0.5 ) ) <= 0 ) {
43+
maxIterations = 0;
44+
}
45+
initialInUnit = initialInUnit / scale;
46+
47+
}
4648

47-
// Update scale, tolerating zero or NaN from tween.cur()
48-
// Break the loop if scale is unchanged or perfect, or if we've just had enough.
49-
} while (
50-
scale !== ( scale = currentValue() / initial ) && scale !== 1 && --maxIterations
51-
);
49+
initialInUnit = initialInUnit * 2;
50+
jQuery.style( elem, prop, initialInUnit + unit );
51+
52+
// Make sure we update the tween properties later on
53+
valueParts = valueParts || [];
5254
}
5355

5456
if ( valueParts ) {

test/unit/css.js

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -271,6 +271,22 @@ QUnit.test( "css() non-px relative values (gh-1711)", function( assert ) {
271271
add( "lineHeight", 50, "%" );
272272
} );
273273

274+
QUnit.test( "css() mismatched relative values with bounded styles (gh-2144)", function( assert ) {
275+
assert.expect( 1 );
276+
277+
var right,
278+
$container = jQuery( "<div/>" )
279+
.css( { position: "absolute", width: "400px", fontSize: "4px" } )
280+
.appendTo( "#qunit-fixture" ),
281+
$el = jQuery( "<div/>" )
282+
.css( { position: "absolute", left: "50%", right: "50%" } )
283+
.appendTo( $container );
284+
285+
$el.css( "right", "-=25em" );
286+
assert.equal( Math.round( parseFloat( $el.css( "right" ) ) ), 100,
287+
"Constraints do not interfere with unit conversion" );
288+
} );
289+
274290
QUnit.test( "css(String, Object)", function( assert ) {
275291
assert.expect( 19 );
276292
var j, div, display, ret, success;

test/unit/effects.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1807,7 +1807,8 @@ QUnit.test( "animate does not change start value for non-px animation (#7109)",
18071807
}
18081808
} ).queue( function( next ) {
18091809
var ratio = computed[ 0 ] / actual;
1810-
assert.ok( ratio > 0.9 && ratio < 1.1, "Starting width was close enough" );
1810+
assert.ok( ratio > 0.9 && ratio < 1.1,
1811+
"Starting width was close enough (" + computed[ 0 ] + " approximates " + actual + ")" );
18111812
next();
18121813
parent.remove();
18131814
} );

0 commit comments

Comments
 (0)