Skip to content

Commit 23212b3

Browse files
committed
CSS: Make .css("width") & .css("height") return fractional values
Fixes gh-1724 Closes gh-2454 Refs gh-2439
1 parent 203979d commit 23212b3

File tree

5 files changed

+117
-27
lines changed

5 files changed

+117
-27
lines changed

src/css.js

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -115,21 +115,28 @@ function augmentWidthOrHeight( elem, name, extra, isBorderBox, styles ) {
115115
function getWidthOrHeight( elem, name, extra ) {
116116

117117
// Start with offset property, which is equivalent to the border-box value
118-
var valueIsBorderBox = true,
119-
val = name === "width" ? elem.offsetWidth : elem.offsetHeight,
118+
var val,
119+
valueIsBorderBox = true,
120120
styles = getStyles( elem ),
121121
isBorderBox = jQuery.css( elem, "boxSizing", false, styles ) === "border-box";
122122

123-
// Support: IE11 only
124-
// In IE 11 fullscreen elements inside of an iframe have
125-
// 100x too small dimensions (gh-1764).
126-
if ( document.msFullscreenElement && window.top !== window ) {
127-
// Support: IE11 only
123+
if ( support.gBCRDimensions() ) {
124+
// Support: IE <= 11 only
128125
// Running getBoundingClientRect on a disconnected node
129126
// in IE throws an error.
130127
if ( elem.getClientRects().length ) {
131-
val = Math.round( elem.getBoundingClientRect()[ name ] * 100 );
128+
val = elem.getBoundingClientRect()[ name ];
132129
}
130+
} else {
131+
// In IE8 gBCR doesn't report width & height; we need to fall back to offset*.
132+
val = name === "width" ? elem.offsetWidth : elem.offsetHeight;
133+
}
134+
135+
// Support: IE11 only
136+
// In IE 11 fullscreen elements inside of an iframe have
137+
// 100x too small dimensions (gh-1764).
138+
if ( document.msFullscreenElement && window.top !== window ) {
139+
val *= 100;
133140
}
134141

135142
// some non-html elements return undefined for offsetWidth, so check for null/undefined
@@ -320,7 +327,13 @@ jQuery.each([ "height", "width" ], function( i, name ) {
320327
// certain elements can have dimension info if we invisibly show them
321328
// however, it must have a current display style that would benefit from this
322329
return rdisplayswap.test( jQuery.css( elem, "display" ) ) &&
323-
elem.offsetWidth === 0 ?
330+
// Support: Safari 8+
331+
// Table columns in Safari have non-zero offsetWidth & zero
332+
// getBoundingClientRect().width unless display is changed.
333+
// Support: IE <= 11 only
334+
// Running getBoundingClientRect on a disconnected node
335+
// in IE throws an error.
336+
( !elem.getClientRects().length || !elem.getBoundingClientRect().width ) ?
324337
swap( elem, cssShow, function() {
325338
return getWidthOrHeight( elem, name, extra );
326339
}) :

src/css/support.js

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@ define([
44
], function( jQuery, support ) {
55

66
(function() {
7-
var div, container, style, a, pixelPositionVal, boxSizingReliableVal, pixelMarginRightVal,
8-
reliableHiddenOffsetsVal, reliableMarginRightVal;
7+
var div, container, style, a, pixelPositionVal, boxSizingReliableVal, gBCRDimensionsVal,
8+
pixelMarginRightVal, reliableHiddenOffsetsVal, reliableMarginRightVal;
99

1010
// Setup
1111
div = document.createElement( "div" );
@@ -55,6 +55,13 @@ define([
5555
return boxSizingReliableVal;
5656
},
5757

58+
gBCRDimensions: function() {
59+
if ( pixelPositionVal == null ) {
60+
computeStyleTests();
61+
}
62+
return gBCRDimensionsVal;
63+
},
64+
5865
pixelMarginRight: function() {
5966
// Support: Android 4.0-4.3
6067
if ( pixelPositionVal == null ) {
@@ -105,6 +112,10 @@ define([
105112
pixelPositionVal = boxSizingReliableVal = false;
106113
pixelMarginRightVal = reliableMarginRightVal = true;
107114

115+
// Support: IE<9
116+
// In IE8 gBCR doesn't report width & height.
117+
gBCRDimensionsVal = !!div.getBoundingClientRect().width;
118+
108119
// Check for getComputedStyle so that this code is not run in IE<9.
109120
if ( window.getComputedStyle ) {
110121
divStyle = window.getComputedStyle( div );

test/unit/css.js

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -904,6 +904,52 @@ testIframeWithCallback( "css('width') should work correctly before document read
904904
}
905905
);
906906

907+
( function() {
908+
var supportsFractionalGBCR,
909+
qunitFixture = document.getElementById( "qunit-fixture" ),
910+
div = document.createElement( "div" );
911+
div.style.width = "3.3px";
912+
qunitFixture.appendChild( div );
913+
supportsFractionalGBCR = jQuery.support.gBCRDimensions() &&
914+
div.getBoundingClientRect().width.toFixed(1) === "3.3";
915+
qunitFixture.removeChild( div );
916+
917+
test( "css('width') and css('height') should return fractional values for nodes in the document", function() {
918+
if ( !supportsFractionalGBCR ) {
919+
expect( 1 );
920+
ok( true, "This browser doesn't support fractional values in getBoundingClientRect()" );
921+
return;
922+
}
923+
924+
expect( 2 );
925+
926+
var el = jQuery( "<div class='test-div'></div>" ).appendTo( "#qunit-fixture" );
927+
jQuery( "<style>.test-div { width: 33.3px; height: 88.8px; }</style>" ).appendTo( "#qunit-fixture" );
928+
929+
equal( Number( el.css( "width" ).replace( /px$/, "" ) ).toFixed( 1 ), "33.3",
930+
"css('width') should return fractional values" );
931+
equal( Number( el.css( "height" ).replace( /px$/, "" ) ).toFixed( 1 ), "88.8",
932+
"css('height') should return fractional values" );
933+
} );
934+
935+
test( "css('width') and css('height') should return fractional values for disconnected nodes", function() {
936+
if ( !supportsFractionalGBCR ) {
937+
expect( 1 );
938+
ok( true, "This browser doesn't support fractional values in getBoundingClientRect()" );
939+
return;
940+
}
941+
942+
expect( 2 );
943+
944+
var el = jQuery( "<div style='width: 33.3px; height: 88.8px;'></div>" );
945+
946+
equal( Number( el.css( "width" ).replace( /px$/, "" ) ).toFixed( 1 ), "33.3",
947+
"css('width') should return fractional values" );
948+
equal( Number( el.css( "height" ).replace( /px$/, "" ) ).toFixed( 1 ), "88.8",
949+
"css('height') should return fractional values" );
950+
} );
951+
} )();
952+
907953
test("certain css values of 'normal' should be convertable to a number, see #8627", function() {
908954
expect ( 3 );
909955

test/unit/dimensions.js

Lines changed: 24 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -258,21 +258,25 @@ test("child of a hidden elem (or unconnected node) has accurate inner/outer/Widt
258258
equal( $divChild.outerWidth(), $divNormal.outerWidth(), "child of a hidden element outerWidth() is wrong see #9441" );
259259
equal( $divChild.outerWidth(true), $divNormal.outerWidth( true ), "child of a hidden element outerWidth( true ) is wrong see #9300" );
260260

261-
equal( $divChild.height(), $divNormal.height(), "child of a hidden element height() is wrong see #9441" );
262-
equal( $divChild.innerHeight(), $divNormal.innerHeight(), "child of a hidden element innerHeight() is wrong see #9441" );
263-
equal( $divChild.outerHeight(), $divNormal.outerHeight(), "child of a hidden element outerHeight() is wrong see #9441" );
264-
equal( $divChild.outerHeight(true), $divNormal.outerHeight( true ), "child of a hidden element outerHeight( true ) is wrong see #9300" );
261+
// Support: IE 10-11, Edge
262+
// Child height is not always decimal
263+
equal( $divChild.height().toFixed( 3 ), $divNormal.height().toFixed( 3 ), "child of a hidden element height() is wrong see #9441" );
264+
equal( $divChild.innerHeight().toFixed( 3 ), $divNormal.innerHeight().toFixed( 3 ), "child of a hidden element innerHeight() is wrong see #9441" );
265+
equal( $divChild.outerHeight().toFixed( 3 ), $divNormal.outerHeight().toFixed( 3 ), "child of a hidden element outerHeight() is wrong see #9441" );
266+
equal( $divChild.outerHeight( true ).toFixed( 3 ), $divNormal.outerHeight( true ).toFixed( 3 ), "child of a hidden element outerHeight( true ) is wrong see #9300" );
265267

266268
// tests that child div of an unconnected div works the same as a normal div
267269
equal( $divUnconnected.width(), $divNormal.width(), "unconnected element width() is wrong see #9441" );
268270
equal( $divUnconnected.innerWidth(), $divNormal.innerWidth(), "unconnected element innerWidth() is wrong see #9441" );
269271
equal( $divUnconnected.outerWidth(), $divNormal.outerWidth(), "unconnected element outerWidth() is wrong see #9441" );
270272
equal( $divUnconnected.outerWidth(true), $divNormal.outerWidth( true ), "unconnected element outerWidth( true ) is wrong see #9300" );
271273

272-
equal( $divUnconnected.height(), $divNormal.height(), "unconnected element height() is wrong see #9441" );
273-
equal( $divUnconnected.innerHeight(), $divNormal.innerHeight(), "unconnected element innerHeight() is wrong see #9441" );
274-
equal( $divUnconnected.outerHeight(), $divNormal.outerHeight(), "unconnected element outerHeight() is wrong see #9441" );
275-
equal( $divUnconnected.outerHeight(true), $divNormal.outerHeight( true ), "unconnected element outerHeight( true ) is wrong see #9300" );
274+
// Support: IE 10-11, Edge
275+
// Child height is not always decimal
276+
equal( $divUnconnected.height().toFixed( 3 ), $divNormal.height().toFixed( 3 ), "unconnected element height() is wrong see #9441" );
277+
equal( $divUnconnected.innerHeight().toFixed( 3 ), $divNormal.innerHeight().toFixed( 3 ), "unconnected element innerHeight() is wrong see #9441" );
278+
equal( $divUnconnected.outerHeight().toFixed( 3 ), $divNormal.outerHeight().toFixed( 3 ), "unconnected element outerHeight() is wrong see #9441" );
279+
equal( $divUnconnected.outerHeight( true ).toFixed( 3 ), $divNormal.outerHeight( true ).toFixed( 3 ), "unconnected element outerHeight( true ) is wrong see #9300" );
276280

277281
// teardown html
278282
$divHiddenParent.remove();
@@ -329,21 +333,25 @@ test("box-sizing:border-box child of a hidden elem (or unconnected node) has acc
329333
equal( $divChild.outerWidth(), $divNormal.outerWidth(), "child of a hidden element outerWidth() is wrong see #10413" );
330334
equal( $divChild.outerWidth(true), $divNormal.outerWidth( true ), "child of a hidden element outerWidth( true ) is wrong see #10413" );
331335

332-
equal( $divChild.height(), $divNormal.height(), "child of a hidden element height() is wrong see #10413" );
333-
equal( $divChild.innerHeight(), $divNormal.innerHeight(), "child of a hidden element innerHeight() is wrong see #10413" );
334-
equal( $divChild.outerHeight(), $divNormal.outerHeight(), "child of a hidden element outerHeight() is wrong see #10413" );
335-
equal( $divChild.outerHeight(true), $divNormal.outerHeight( true ), "child of a hidden element outerHeight( true ) is wrong see #10413" );
336+
// Support: IE 10-11, Edge
337+
// Child height is not always decimal
338+
equal( $divChild.height().toFixed( 3 ), $divNormal.height().toFixed( 3 ), "child of a hidden element height() is wrong see #10413" );
339+
equal( $divChild.innerHeight().toFixed( 3 ), $divNormal.innerHeight().toFixed( 3 ), "child of a hidden element innerHeight() is wrong see #10413" );
340+
equal( $divChild.outerHeight().toFixed( 3 ), $divNormal.outerHeight().toFixed( 3 ), "child of a hidden element outerHeight() is wrong see #10413" );
341+
equal( $divChild.outerHeight( true ).toFixed( 3 ), $divNormal.outerHeight( true ).toFixed( 3 ), "child of a hidden element outerHeight( true ) is wrong see #10413" );
336342

337343
// tests that child div of an unconnected div works the same as a normal div
338344
equal( $divUnconnected.width(), $divNormal.width(), "unconnected element width() is wrong see #10413" );
339345
equal( $divUnconnected.innerWidth(), $divNormal.innerWidth(), "unconnected element innerWidth() is wrong see #10413" );
340346
equal( $divUnconnected.outerWidth(), $divNormal.outerWidth(), "unconnected element outerWidth() is wrong see #10413" );
341347
equal( $divUnconnected.outerWidth(true), $divNormal.outerWidth( true ), "unconnected element outerWidth( true ) is wrong see #10413" );
342348

343-
equal( $divUnconnected.height(), $divNormal.height(), "unconnected element height() is wrong see #10413" );
344-
equal( $divUnconnected.innerHeight(), $divNormal.innerHeight(), "unconnected element innerHeight() is wrong see #10413" );
345-
equal( $divUnconnected.outerHeight(), $divNormal.outerHeight(), "unconnected element outerHeight() is wrong see #10413" );
346-
equal( $divUnconnected.outerHeight(true), $divNormal.outerHeight( true ), "unconnected element outerHeight( true ) is wrong see #10413" );
349+
// Support: IE 10-11, Edge
350+
// Child height is not always decimal
351+
equal( $divUnconnected.height().toFixed( 3 ), $divNormal.height().toFixed( 3 ), "unconnected element height() is wrong see #10413" );
352+
equal( $divUnconnected.innerHeight().toFixed( 3 ), $divNormal.innerHeight().toFixed( 3 ), "unconnected element innerHeight() is wrong see #10413" );
353+
equal( $divUnconnected.outerHeight().toFixed( 3 ), $divNormal.outerHeight().toFixed( 3 ), "unconnected element outerHeight() is wrong see #10413" );
354+
equal( $divUnconnected.outerHeight( true ).toFixed( 3 ), $divNormal.outerHeight( true ).toFixed( 3 ), "unconnected element outerHeight( true ) is wrong see #10413" );
347355

348356
// teardown html
349357
$divHiddenParent.remove();

test/unit/support.js

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ testIframeWithCallback( "Check CSP (https://developer.mozilla.org/en-US/docs/Sec
8282
"cssFloat": true,
8383
"deleteExpando": true,
8484
"focusin": false,
85+
"gBCRDimensions": true,
8586
"html5Clone": true,
8687
"htmlSerialize": true,
8788
"input": true,
@@ -114,6 +115,7 @@ testIframeWithCallback( "Check CSP (https://developer.mozilla.org/en-US/docs/Sec
114115
"cssFloat": true,
115116
"deleteExpando": true,
116117
"focusin": true,
118+
"gBCRDimensions": true,
117119
"html5Clone": true,
118120
"htmlSerialize": true,
119121
"input": true,
@@ -146,6 +148,7 @@ testIframeWithCallback( "Check CSP (https://developer.mozilla.org/en-US/docs/Sec
146148
"cssFloat": true,
147149
"deleteExpando": true,
148150
"focusin": true,
151+
"gBCRDimensions": true,
149152
"html5Clone": true,
150153
"htmlSerialize": true,
151154
"input": true,
@@ -178,6 +181,7 @@ testIframeWithCallback( "Check CSP (https://developer.mozilla.org/en-US/docs/Sec
178181
"cssFloat": false,
179182
"deleteExpando": false,
180183
"focusin": true,
184+
"gBCRDimensions": false,
181185
"html5Clone": false,
182186
"htmlSerialize": false,
183187
"input": false,
@@ -212,6 +216,7 @@ testIframeWithCallback( "Check CSP (https://developer.mozilla.org/en-US/docs/Sec
212216
"cssFloat": true,
213217
"deleteExpando": true,
214218
"focusin": false,
219+
"gBCRDimensions": true,
215220
"html5Clone": true,
216221
"htmlSerialize": true,
217222
"input": true,
@@ -244,6 +249,7 @@ testIframeWithCallback( "Check CSP (https://developer.mozilla.org/en-US/docs/Sec
244249
"cssFloat": true,
245250
"deleteExpando": true,
246251
"focusin": false,
252+
"gBCRDimensions": true,
247253
"html5Clone": true,
248254
"htmlSerialize": true,
249255
"input": true,
@@ -276,6 +282,7 @@ testIframeWithCallback( "Check CSP (https://developer.mozilla.org/en-US/docs/Sec
276282
"cssFloat": true,
277283
"deleteExpando": true,
278284
"focusin": false,
285+
"gBCRDimensions": true,
279286
"html5Clone": true,
280287
"htmlSerialize": true,
281288
"input": true,
@@ -308,6 +315,7 @@ testIframeWithCallback( "Check CSP (https://developer.mozilla.org/en-US/docs/Sec
308315
"cssFloat": true,
309316
"deleteExpando": true,
310317
"focusin": false,
318+
"gBCRDimensions": true,
311319
"html5Clone": true,
312320
"htmlSerialize": true,
313321
"input": true,
@@ -340,6 +348,7 @@ testIframeWithCallback( "Check CSP (https://developer.mozilla.org/en-US/docs/Sec
340348
"cssFloat": true,
341349
"deleteExpando": true,
342350
"focusin": false,
351+
"gBCRDimensions": true,
343352
"html5Clone": true,
344353
"htmlSerialize": true,
345354
"input": true,
@@ -372,6 +381,7 @@ testIframeWithCallback( "Check CSP (https://developer.mozilla.org/en-US/docs/Sec
372381
"cssFloat": true,
373382
"deleteExpando": true,
374383
"focusin": false,
384+
"gBCRDimensions": true,
375385
"html5Clone": true,
376386
"htmlSerialize": true,
377387
"input": true,
@@ -404,6 +414,7 @@ testIframeWithCallback( "Check CSP (https://developer.mozilla.org/en-US/docs/Sec
404414
"cssFloat": true,
405415
"deleteExpando": true,
406416
"focusin": false,
417+
"gBCRDimensions": true,
407418
"html5Clone": true,
408419
"htmlSerialize": true,
409420
"input": true,
@@ -436,6 +447,7 @@ testIframeWithCallback( "Check CSP (https://developer.mozilla.org/en-US/docs/Sec
436447
"cssFloat": true,
437448
"deleteExpando": true,
438449
"focusin": false,
450+
"gBCRDimensions": true,
439451
"html5Clone": true,
440452
"htmlSerialize": true,
441453
"input": true,

0 commit comments

Comments
 (0)