diff --git a/src/css.js b/src/css.js index c1775b7ab..afbf96afb 100644 --- a/src/css.js +++ b/src/css.js @@ -13,12 +13,35 @@ var ralpha = /alpha\([^)]*\)/i, // order is important! cssExpand = [ "Top", "Right", "Bottom", "Left" ], + cssPrefixes = [ "O", "Webkit", "Moz", "ms" ], curCSS, - getComputedStyle, currentStyle; +// return a css property mapped to a potentially vendor prefixed property +function vendorPropName( style, name ) { + + // shortcut for names that are not vendor prefixed + if ( name in style ) { + return name; + } + + // check for vendor prefixed names + var capName = name.charAt(0).toUpperCase() + name.slice(1), + origName = name, + i = cssPrefixes.length; + + while ( i-- ) { + name = cssPrefixes[ i ] + capName; + if ( name in style ) { + return name; + } + } + + return origName; +} + jQuery.fn.css = function( name, value ) { return jQuery.access( this, function( elem, name, value ) { return value !== undefined ? @@ -72,10 +95,15 @@ jQuery.extend({ } // Make sure that we're working with the right name - var ret, type, origName = jQuery.camelCase( name ), - style = elem.style, hooks = jQuery.cssHooks[ origName ]; + var ret, type, hooks, + origName = jQuery.camelCase( name ), + style = elem.style; - name = jQuery.cssProps[ origName ] || origName; + name = jQuery.cssProps[ origName ] || ( jQuery.cssProps[ origName ] = vendorPropName( style, origName ) ); + + // gets hook for the prefixed version + // followed by the unprefixed version + hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ]; // Check if we're setting a value if ( value !== undefined ) { @@ -119,12 +147,15 @@ jQuery.extend({ }, css: function( elem, name, extra ) { - var ret, hooks; + var ret, hooks, + origName = jQuery.camelCase( name ); // Make sure that we're working with the right name - name = jQuery.camelCase( name ); - hooks = jQuery.cssHooks[ name ]; - name = jQuery.cssProps[ name ] || name; + name = jQuery.cssProps[ origName ] || ( jQuery.cssProps[ origName ] = vendorPropName( elem.style, origName ) ); + + // gets hook for the prefixed version + // followed by the unprefixed version + hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ]; // cssFloat needs a special treatment if ( name === "cssFloat" ) { @@ -244,9 +275,29 @@ function getWidthOrHeight( elem, name, extra ) { // Start with offset property var val = name === "width" ? elem.offsetWidth : elem.offsetHeight, i = name === "width" ? 1 : 0, - len = 4; + len = 4, + usedOffset = true; - if ( val > 0 ) { + if ( val <= 0 ) { + usedOffset = false; + + // Fall back to computed then uncomputed css if necessary + val = curCSS( elem, name ); + if ( val < 0 || val == null ) { + val = elem.style[ name ]; + } + + // Computed unit is not pixels. Stop here and return. + if ( rnumnonpx.test(val) ) { + return val; + } + + // Normalize "", auto, and prepare for extra + val = parseFloat( val ) || 0; + } + + //if we're using border-box, the css width/height value behaves like the offsetWidth/Height property! + if ( usedOffset || ( jQuery.support.boxSizing && jQuery.css( elem, "boxSizing" ) === "border-box" ) ) { if ( extra !== "border" ) { for ( ; i < len; i += 2 ) { if ( !extra ) { @@ -259,33 +310,17 @@ function getWidthOrHeight( elem, name, extra ) { } } } - - return val + "px"; - } - - // Fall back to computed then uncomputed css if necessary - val = curCSS( elem, name ); - if ( val < 0 || val == null ) { - val = elem.style[ name ]; - } - - // Computed unit is not pixels. Stop here and return. - if ( rnumnonpx.test(val) ) { - return val; - } - - // Normalize "", auto, and prepare for extra - val = parseFloat( val ) || 0; - - // Add padding, border, margin - if ( extra ) { - for ( ; i < len; i += 2 ) { - val += parseFloat( jQuery.css( elem, "padding" + cssExpand[ i ] ) ) || 0; - if ( extra !== "padding" ) { - val += parseFloat( jQuery.css( elem, "border" + cssExpand[ i ] + "Width" ) ) || 0; - } - if ( extra === "margin" ) { - val += parseFloat( jQuery.css( elem, extra + cssExpand[ i ]) ) || 0; + } else { + // Add padding, border, margin + if ( extra ) { + for ( ; i < len; i += 2 ) { + val += parseFloat( jQuery.css( elem, "padding" + cssExpand[ i ] ) ) || 0; + if ( extra !== "padding" ) { + val += parseFloat( jQuery.css( elem, "border" + cssExpand[ i ] + "Width" ) ) || 0; + } + if ( extra === "margin" ) { + val += parseFloat( jQuery.css( elem, extra + cssExpand[ i ] ) ) || 0; + } } } } diff --git a/src/support.js b/src/support.js index 5a0d1b731..ccf9d4315 100644 --- a/src/support.js +++ b/src/support.js @@ -180,6 +180,7 @@ jQuery.support = (function() { jQuery(function() { var container, offsetSupport, marginDiv, conMarginTop = 1, + boxSizingPrefixes = [ "", "-moz-", "-webkit-", "" ], body = document.getElementsByTagName("body")[0]; if ( !body ) { @@ -250,6 +251,9 @@ jQuery.support = (function() { support.shrinkWrapBlocks = ( div.offsetWidth !== 3 ); } + div.style.cssText = boxSizingPrefixes.join("box-sizing:border-box;") + "width:4px;padding:1px;border:1px;display:block"; + support.boxSizing = ( div.offsetWidth === 4 ); + offsetSupport = { doesNotIncludeMarginInBodyOffset: ( body.offsetTop !== conMarginTop ) }; diff --git a/test/unit/dimensions.js b/test/unit/dimensions.js index c6b8e835c..ef3d8ca68 100644 --- a/test/unit/dimensions.js +++ b/test/unit/dimensions.js @@ -230,12 +230,13 @@ test("outerWidth()", function() { jQuery.removeData($div[0], "olddisplay", true); }); -test("child of a hidden elem has accurate inner/outer/Width()/Height() see #9441 #9300", function() { - expect(8); +test("child of a hidden elem (or unconnected node) has accurate inner/outer/Width()/Height() see #9441 #9300", function() { + expect(16); // setup html - var $divNormal = jQuery("
").css({ width: "100px", height: "100px", border: "10px solid white", padding: "2px", margin: "3px" }), - $divChild = $divNormal.clone(), + var $divNormal = jQuery("
").css({ width: "100px", height: "100px", border: "10px solid white", padding: "2px", margin: "3px" }), + $divChild = $divNormal.clone(), + $divUnconnected = $divNormal.clone(), $divHiddenParent = jQuery("
").css( "display", "none" ).append( $divChild ).appendTo("body"); $divNormal.appendTo("body"); @@ -250,6 +251,17 @@ test("child of a hidden elem has accurate inner/outer/Width()/Height() see #944 equal( $divChild.outerHeight(), $divNormal.outerHeight(), "child of a hidden element outerHeight() is wrong see #9441" ); equal( $divChild.outerHeight(true), $divNormal.outerHeight( true ), "child of a hidden element outerHeight( true ) is wrong see #9300" ); + // tests that child div of an unconnected div works the same as a normal div + equal( $divUnconnected.width(), $divNormal.width(), "unconnected element width() is wrong see #9441" ); + equal( $divUnconnected.innerWidth(), $divNormal.innerWidth(), "unconnected element innerWidth() is wrong see #9441" ); + equal( $divUnconnected.outerWidth(), $divNormal.outerWidth(), "unconnected element outerWidth() is wrong see #9441" ); + equal( $divUnconnected.outerWidth(true), $divNormal.outerWidth( true ), "unconnected element outerWidth( true ) is wrong see #9300" ); + + equal( $divUnconnected.height(), $divNormal.height(), "unconnected element height() is wrong see #9441" ); + equal( $divUnconnected.innerHeight(), $divNormal.innerHeight(), "unconnected element innerHeight() is wrong see #9441" ); + equal( $divUnconnected.outerHeight(), $divNormal.outerHeight(), "unconnected element outerHeight() is wrong see #9441" ); + equal( $divUnconnected.outerHeight(true), $divNormal.outerHeight( true ), "unconnected element outerHeight( true ) is wrong see #9300" ); + // teardown html $divHiddenParent.remove(); $divNormal.remove(); @@ -278,6 +290,43 @@ test("getting dimensions shouldnt modify runtimeStyle see #9233", function() { $div.remove(); }); +test("box-sizing:border-box child of a hidden elem (or unconnected node) has accurate inner/outer/Width()/Height() see #10413", function() { + expect(16); + + // setup html + var $divNormal = jQuery("
").css({ boxSizing: "border-box", width: "100px", height: "100px", border: "10px solid white", padding: "2px", margin: "3px" }), + $divChild = $divNormal.clone(), + $divUnconnected = $divNormal.clone(), + $divHiddenParent = jQuery("
").css( "display", "none" ).append( $divChild ).appendTo("body"); + $divNormal.appendTo("body"); + + // tests that child div of a hidden div works the same as a normal div + equal( $divChild.width(), $divNormal.width(), "child of a hidden element width() is wrong see #10413" ); + equal( $divChild.innerWidth(), $divNormal.innerWidth(), "child of a hidden element innerWidth() is wrong see #10413" ); + equal( $divChild.outerWidth(), $divNormal.outerWidth(), "child of a hidden element outerWidth() is wrong see #10413" ); + equal( $divChild.outerWidth(true), $divNormal.outerWidth( true ), "child of a hidden element outerWidth( true ) is wrong see #10413" ); + + equal( $divChild.height(), $divNormal.height(), "child of a hidden element height() is wrong see #10413" ); + equal( $divChild.innerHeight(), $divNormal.innerHeight(), "child of a hidden element innerHeight() is wrong see #10413" ); + equal( $divChild.outerHeight(), $divNormal.outerHeight(), "child of a hidden element outerHeight() is wrong see #10413" ); + equal( $divChild.outerHeight(true), $divNormal.outerHeight( true ), "child of a hidden element outerHeight( true ) is wrong see #10413" ); + + // tests that child div of an unconnected div works the same as a normal div + equal( $divUnconnected.width(), $divNormal.width(), "unconnected element width() is wrong see #10413" ); + equal( $divUnconnected.innerWidth(), $divNormal.innerWidth(), "unconnected element innerWidth() is wrong see #10413" ); + equal( $divUnconnected.outerWidth(), $divNormal.outerWidth(), "unconnected element outerWidth() is wrong see #10413" ); + equal( $divUnconnected.outerWidth(true), $divNormal.outerWidth( true ), "unconnected element outerWidth( true ) is wrong see #10413" ); + + equal( $divUnconnected.height(), $divNormal.height(), "unconnected element height() is wrong see #10413" ); + equal( $divUnconnected.innerHeight(), $divNormal.innerHeight(), "unconnected element innerHeight() is wrong see #10413" ); + equal( $divUnconnected.outerHeight(), $divNormal.outerHeight(), "unconnected element outerHeight() is wrong see #10413" ); + equal( $divUnconnected.outerHeight(true), $divNormal.outerHeight( true ), "unconnected element outerHeight( true ) is wrong see #10413" ); + + // teardown html + $divHiddenParent.remove(); + $divNormal.remove(); +}); + test("outerHeight()", function() { expect(11);