Permalink
Browse files

CSS: Avoid unit-conversion interference from CSS upper bounds

Fixes gh-2144
Closes gh-3745
  • Loading branch information...
gibson042 committed Aug 28, 2017
1 parent b1b949d commit 692f9d4db30c9c6c4f6bc76005cf153586202fa6
Showing with 37 additions and 18 deletions.
  1. +19 −17 src/css/adjustCSS.js
  2. +16 −0 test/unit/css.js
  3. +2 −1 test/unit/effects.js
@@ -6,8 +6,7 @@ define( [
"use strict";
function adjustCSS( elem, prop, valueParts, tween ) {
var adjusted,
scale = 1,
var adjusted, scale,
maxIterations = 20,
currentValue = tween ?
function() {
@@ -25,30 +24,33 @@ function adjustCSS( elem, prop, valueParts, tween ) {
if ( initialInUnit && initialInUnit[ 3 ] !== unit ) {
// Support: Firefox <=54
// Halve the iteration target value to prevent interference from CSS upper bounds (gh-2144)
initial = initial / 2;
// Trust units reported by jQuery.css
unit = unit || initialInUnit[ 3 ];
// Make sure we update the tween properties later on
valueParts = valueParts || [];
// Iteratively approximate from a nonzero starting point
initialInUnit = +initial || 1;
do {
// If previous iteration zeroed out, double until we get *something*.
// Use string for doubling so we don't accidentally see scale as unchanged below
scale = scale || ".5";
while ( maxIterations-- ) {
// Adjust and apply
initialInUnit = initialInUnit / scale;
// Evaluate and update our best guess (doubling guesses that zero out).
// Finish if the scale equals or crosses 1 (making the old*new product non-positive).
jQuery.style( elem, prop, initialInUnit + unit );
if ( ( 1 - scale ) * ( 1 - ( scale = currentValue() / initial || 0.5 ) ) <= 0 ) {
maxIterations = 0;
}
initialInUnit = initialInUnit / scale;
}
// Update scale, tolerating zero or NaN from tween.cur()
// Break the loop if scale is unchanged or perfect, or if we've just had enough.
} while (
scale !== ( scale = currentValue() / initial ) && scale !== 1 && --maxIterations
);
initialInUnit = initialInUnit * 2;
jQuery.style( elem, prop, initialInUnit + unit );
// Make sure we update the tween properties later on
valueParts = valueParts || [];
}
if ( valueParts ) {
@@ -271,6 +271,22 @@ QUnit.test( "css() non-px relative values (gh-1711)", function( assert ) {
add( "lineHeight", 50, "%" );
} );
QUnit.test( "css() mismatched relative values with bounded styles (gh-2144)", function( assert ) {
assert.expect( 1 );
var right,
$container = jQuery( "<div/>" )
.css( { position: "absolute", width: "400px", fontSize: "4px" } )
.appendTo( "#qunit-fixture" ),
$el = jQuery( "<div/>" )
.css( { position: "absolute", left: "50%", right: "50%" } )
.appendTo( $container );
$el.css( "right", "-=25em" );
assert.equal( Math.round( parseFloat( $el.css( "right" ) ) ), 100,
"Constraints do not interfere with unit conversion" );
} );
QUnit.test( "css(String, Object)", function( assert ) {
assert.expect( 19 );
var j, div, display, ret, success;
@@ -1807,7 +1807,8 @@ QUnit.test( "animate does not change start value for non-px animation (#7109)",
}
} ).queue( function( next ) {
var ratio = computed[ 0 ] / actual;
assert.ok( ratio > 0.9 && ratio < 1.1, "Starting width was close enough" );
assert.ok( ratio > 0.9 && ratio < 1.1,
"Starting width was close enough (" + computed[ 0 ] + " approximates " + actual + ")" );
next();
parent.remove();
} );

0 comments on commit 692f9d4

Please sign in to comment.