From 3fcddd6e72e7e318c0b062e391d60867732318ae Mon Sep 17 00:00:00 2001 From: Richard Gibson Date: Mon, 10 Jul 2017 12:35:03 -0400 Subject: [PATCH] Dimensions: Detect and account for content-box dimension mishandling Fixes gh-3699 Closes gh-3700 --- src/css.js | 22 +++++++++++++++++----- src/css/support.js | 21 +++++++++++++++------ test/unit/dimensions.js | 17 ++++++++++++----- 3 files changed, 44 insertions(+), 16 deletions(-) diff --git a/src/css.js b/src/css.js index 5da9a3aea..79e06319c 100644 --- a/src/css.js +++ b/src/css.js @@ -148,10 +148,10 @@ function boxModelAdjustment( elem, dimension, box, isBorderBox, styles, computed function getWidthOrHeight( elem, dimension, extra ) { // Start with computed style - var valueIsBorderBox, - styles = getStyles( elem ), + var styles = getStyles( elem ), val = curCSS( elem, dimension, styles ), - isBorderBox = jQuery.css( elem, "boxSizing", false, styles ) === "border-box"; + isBorderBox = jQuery.css( elem, "boxSizing", false, styles ) === "border-box", + valueIsBorderBox = isBorderBox; // Computed unit is not pixels. Stop here and return. if ( rnumnonpx.test( val ) ) { @@ -160,7 +160,7 @@ function getWidthOrHeight( elem, dimension, extra ) { // Check for style in case a browser which returns unreliable values // for getComputedStyle silently falls back to the reliable elem.style - valueIsBorderBox = isBorderBox && + valueIsBorderBox = valueIsBorderBox && ( support.boxSizingReliable() || val === elem.style[ dimension ] ); // Fall back to offsetWidth/Height when value is "auto" @@ -367,14 +367,26 @@ jQuery.each( [ "height", "width" ], function( i, dimension ) { set: function( elem, value, extra ) { var matches, styles = getStyles( elem ), + isBorderBox = jQuery.css( elem, "boxSizing", false, styles ) === "border-box", subtract = extra && boxModelAdjustment( elem, dimension, extra, - jQuery.css( elem, "boxSizing", false, styles ) === "border-box", + isBorderBox, styles ); + // Account for unreliable border-box dimensions by comparing offset* to computed and + // faking a content-box to get border and padding (gh-3699) + if ( isBorderBox && !support.borderBoxReliable() ) { + subtract -= Math.ceil( + elem[ "offset" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 ) ] - + parseFloat( styles[ dimension ] ) - + boxModelAdjustment( elem, dimension, "border", false, styles ) - + 0.5 + ); + } + // Convert to pixels if value adjustment is needed if ( subtract && ( matches = rcssNum.exec( value ) ) && ( matches[ 3 ] || "px" ) !== "px" ) { diff --git a/src/css/support.js b/src/css/support.js index 883d0e53e..7b7945fef 100644 --- a/src/css/support.js +++ b/src/css/support.js @@ -31,12 +31,16 @@ define( [ // Support: Android 4.0 - 4.3 only, Firefox <=3 - 44 reliableMarginLeftVal = divStyle.marginLeft === "2px"; - boxSizingReliableVal = divStyle.width === "4px"; + boxSizingReliableVal = divStyle.width === "5px"; + + // Support: IE 9 only + // Detect misreporting of content dimensions for border-box elements (gh-3699) + borderBoxReliableVal = divStyle.width[ 0 ] === "5"; // Support: Android 4.0 - 4.3 only // Some styles come back with percentage values, even though they shouldn't div.style.marginRight = "50%"; - pixelMarginRightVal = divStyle.marginRight === "4px"; + pixelMarginRightVal = divStyle.marginRight === "5px"; documentElement.removeChild( container ); @@ -45,7 +49,8 @@ define( [ div = null; } - var pixelPositionVal, boxSizingReliableVal, pixelMarginRightVal, reliableMarginLeftVal, + var pixelPositionVal, boxSizingReliableVal, borderBoxReliableVal, pixelMarginRightVal, + reliableMarginLeftVal, container = document.createElement( "div" ), div = document.createElement( "div" ); @@ -60,19 +65,23 @@ define( [ div.cloneNode( true ).style.backgroundClip = ""; support.clearCloneStyle = div.style.backgroundClip === "content-box"; - container.style.cssText = "border:0;width:8px;height:0;top:0;left:-9999px;" + + container.style.cssText = "border:0;width:10px;height:0;top:0;left:-9999px;" + "padding:0;margin-top:1px;position:absolute"; container.appendChild( div ); jQuery.extend( support, { - pixelPosition: function() { + borderBoxReliable: function() { computeStyleTests(); - return pixelPositionVal; + return borderBoxReliableVal; }, boxSizingReliable: function() { computeStyleTests(); return boxSizingReliableVal; }, + pixelPosition: function() { + computeStyleTests(); + return pixelPositionVal; + }, pixelMarginRight: function() { computeStyleTests(); return pixelMarginRightVal; diff --git a/test/unit/dimensions.js b/test/unit/dimensions.js index 2ec5f3683..5db465868 100644 --- a/test/unit/dimensions.js +++ b/test/unit/dimensions.js @@ -585,7 +585,14 @@ QUnit.test( "interaction with scrollbars (gh-3589)", function( assert ) { .css( borderBox ) .css( { "box-sizing": "border-box" } ) .appendTo( parent ), - $boxes = jQuery( [ plainContentBox[ 0 ], contentBox[ 0 ], borderBox[ 0 ] ] ); + $boxes = jQuery( [ plainContentBox[ 0 ], contentBox[ 0 ], borderBox[ 0 ] ] ), + + // Support: IE 9 only + // Computed width seems to report content width even with "box-sizing: border-box", and + // "overflow: scroll" actually _shrinks_ the element (gh-3699). + borderBoxLoss = + borderBox.clone().css( { overflow: "auto" } ).appendTo( parent )[ 0 ].offsetWidth - + borderBox[ 0 ].offsetWidth; for ( i = 0; i < 3; i++ ) { if ( i === 1 ) { @@ -616,13 +623,13 @@ QUnit.test( "interaction with scrollbars (gh-3589)", function( assert ) { assert.equal( contentBox.outerHeight(), size + 2 * padding + 2 * borderWidth, "content-box outerHeight includes scroll gutter" + suffix ); - assert.equal( borderBox.innerWidth(), size - 2 * borderWidth, + assert.equal( borderBox.innerWidth(), size - borderBoxLoss - 2 * borderWidth, "border-box innerWidth includes scroll gutter" + suffix ); - assert.equal( borderBox.innerHeight(), size - 2 * borderWidth, + assert.equal( borderBox.innerHeight(), size - borderBoxLoss - 2 * borderWidth, "border-box innerHeight includes scroll gutter" + suffix ); - assert.equal( borderBox.outerWidth(), size, + assert.equal( borderBox.outerWidth(), size - borderBoxLoss, "border-box outerWidth includes scroll gutter" + suffix ); - assert.equal( borderBox.outerHeight(), size, + assert.equal( borderBox.outerHeight(), size - borderBoxLoss, "border-box outerHeight includes scroll gutter" + suffix ); } } ); -- 2.39.5