diff options
-rw-r--r-- | src/css.js | 50 | ||||
-rw-r--r-- | src/css/support.js | 134 | ||||
-rw-r--r-- | test/unit/dimensions.js | 89 | ||||
-rw-r--r-- | test/unit/event.js | 2 | ||||
-rw-r--r-- | test/unit/support.js | 8 |
5 files changed, 192 insertions, 91 deletions
diff --git a/src/css.js b/src/css.js index 3e7073507..66e5c3c75 100644 --- a/src/css.js +++ b/src/css.js @@ -18,13 +18,7 @@ import { support } from "./css/support.js"; import "./core/init.js"; import "./core/ready.js"; -var - - // Swappable if display is none or starts with table - // except "table", "table-cell", or "table-caption" - // See here for display values: https://developer.mozilla.org/en-US/docs/CSS/display - rdisplayswap = /^(none|table(?!-c[ea]).+)/, - cssShow = { position: "absolute", visibility: "hidden", display: "block" }, +var cssShow = { position: "absolute", visibility: "hidden", display: "block" }, cssNormalTransform = { letterSpacing: "0", fontWeight: "400" @@ -137,24 +131,22 @@ function getWidthOrHeight( elem, dimension, extra ) { } - if ( ( + if ( + ( + + // Fall back to offsetWidth/offsetHeight when value is "auto" + // This happens for inline elements with no explicit setting (gh-3571) + val === "auto" || - // Fall back to offsetWidth/offsetHeight when value is "auto" - // This happens for inline elements with no explicit setting (gh-3571) - val === "auto" || + // Support: IE 9 - 11+ + // Use offsetWidth/offsetHeight for when box sizing is unreliable. + // In those cases, the computed value can be trusted to be border-box. + ( isIE && isBorderBox ) || - // Support: IE 9 - 11+ - // Use offsetWidth/offsetHeight for when box sizing is unreliable. - // In those cases, the computed value can be trusted to be border-box. - ( isIE && isBorderBox ) || + ( !support.reliableColDimensions() && nodeName( elem, "col" ) ) || - // Support: IE 10 - 11+ - // IE misreports `getComputedStyle` of table rows with width/height - // set in CSS while `offset*` properties report correct values. - // Support: Firefox 70 - 135+ - // Firefox includes border widths - // in computed dimensions for table rows. (gh-4529) - ( !support.reliableTrDimensions() && nodeName( elem, "tr" ) ) ) && + ( !support.reliableTrDimensions() && nodeName( elem, "tr" ) ) + ) && // Make sure the element is visible & connected elem.getClientRects().length ) { @@ -316,17 +308,9 @@ jQuery.each( [ "height", "width" ], function( _i, dimension ) { get: function( elem, computed, extra ) { if ( computed ) { - // Certain elements can have dimension info if we invisibly show them - // but it must have a current display style that would benefit - return rdisplayswap.test( jQuery.css( elem, "display" ) ) && - - // Support: Safari <=8 - 12+, Chrome <=73+ - // Table columns in WebKit/Blink have non-zero offsetWidth & zero - // getBoundingClientRect().width unless display is changed. - // Support: IE <=11+ - // Running getBoundingClientRect on a disconnected node - // in IE throws an error. - ( !elem.getClientRects().length || !elem.getBoundingClientRect().width ) ? + // Elements with `display: none` can have dimension info if + // we invisibly show them. + return jQuery.css( elem, "display" ) === "none" ? swap( elem, cssShow, function() { return getWidthOrHeight( elem, dimension, extra ); } ) : diff --git a/src/css/support.js b/src/css/support.js index bca0b6dbf..a05d31bd1 100644 --- a/src/css/support.js +++ b/src/css/support.js @@ -1,62 +1,96 @@ +import { jQuery } from "../core.js"; import { document } from "../var/document.js"; import { documentElement } from "../var/documentElement.js"; import { support } from "../var/support.js"; +import { isIE } from "../var/isIE.js"; -( function() { +var reliableTrDimensionsVal, reliableColDimensionsVal, + table = document.createElement( "table" ); -var reliableTrDimensionsVal, - div = document.createElement( "div" ); +// Executing table tests requires only one layout, so they're executed +// at the same time to save the second computation. +function computeTableStyleTests() { + if ( -// Finish early in limited (non-browser) environments -if ( !div.style ) { - return; -} + // This is a singleton, we need to execute it only once + !table || + + // Finish early in limited (non-browser) environments + !table.style + ) { + return; + } + + var trStyle, + col = document.createElement( "col" ), + tr = document.createElement( "tr" ), + td = document.createElement( "td" ); -// Support: IE 10 - 11+ -// IE misreports `getComputedStyle` of table rows with width/height -// set in CSS while `offset*` properties report correct values. -// Support: Firefox 70+ -// Only Firefox includes border widths -// in computed dimensions. (gh-4529) -support.reliableTrDimensions = function() { - var table, tr, trStyle; - if ( reliableTrDimensionsVal == null ) { - table = document.createElement( "table" ); - tr = document.createElement( "tr" ); - - table.style.cssText = "position:absolute;left:-11111px;border-collapse:separate"; - tr.style.cssText = "box-sizing:content-box;border:1px solid;height:1px"; - div.style.height = "9px"; - - // Support: Android Chrome 86+ - // In our bodyBackground.html iframe, - // display for all div elements is set to "inline", - // which causes a problem only in Android Chrome, but - // not consistently across all devices. - // Ensuring the div is `display: block` - // gets around this issue. - div.style.display = "block"; - - documentElement - .appendChild( table ) - .appendChild( tr ) - .appendChild( div ); - - // Don't run until window is visible - if ( table.offsetWidth === 0 ) { - documentElement.removeChild( table ); - return; - } - - trStyle = window.getComputedStyle( tr ); - reliableTrDimensionsVal = ( Math.round( parseFloat( trStyle.height ) ) + - Math.round( parseFloat( trStyle.borderTopWidth ) ) + - Math.round( parseFloat( trStyle.borderBottomWidth ) ) ) === tr.offsetHeight; + table.style.cssText = "position:absolute;left:-11111px;" + + "border-collapse:separate;border-spacing:0"; + tr.style.cssText = "box-sizing:content-box;border:1px solid;height:1px"; + td.style.cssText = "height:9px;width:9px;padding:0"; + col.span = 2; + + documentElement + .appendChild( table ) + .appendChild( col ) + .parentNode + .appendChild( tr ) + .appendChild( td ) + .parentNode + .appendChild( td.cloneNode( true ) ); + + // Don't run until window is visible + if ( table.offsetWidth === 0 ) { documentElement.removeChild( table ); + return; + } + + trStyle = window.getComputedStyle( tr ); + + // Support: Firefox 135+ + // Firefox always reports computed width as if `span` was 1. + // Support: Safari 18.3+ + // In Safari, computed width for columns is always 0. + // In both these browsers, using `offsetWidth` solves the issue. + // Support: IE 11+ + // In IE, `<col>` computed width is `"auto"` unless `width` is set + // explicitly via CSS so measurements there remain incorrect. Because of + // the lack of a proper workaround, we accept this limitation, treating + // IE as passing the test. + reliableColDimensionsVal = isIE || Math.round( parseFloat( + window.getComputedStyle( col ).width ) + ) === 18; + + // Support: IE 10 - 11+ + // IE misreports `getComputedStyle` of table rows with width/height + // set in CSS while `offset*` properties report correct values. + // Support: Firefox 70 - 135+ + // Only Firefox includes border widths + // in computed dimensions for table rows. (gh-4529) + reliableTrDimensionsVal = Math.round( parseFloat( trStyle.height ) + + parseFloat( trStyle.borderTopWidth ) + + parseFloat( trStyle.borderBottomWidth ) ) === tr.offsetHeight; + + documentElement.removeChild( table ); + + // Nullify the table so it wouldn't be stored in the memory; + // it will also be a sign that checks were already performed. + table = null; +} + +jQuery.extend( support, { + reliableTrDimensions: function() { + computeTableStyleTests(); + return reliableTrDimensionsVal; + }, + + reliableColDimensions: function() { + computeTableStyleTests(); + return reliableColDimensionsVal; } - return reliableTrDimensionsVal; -}; -} )(); +} ); export { support }; diff --git a/test/unit/dimensions.js b/test/unit/dimensions.js index 93cdb3d82..3a8b988f1 100644 --- a/test/unit/dimensions.js +++ b/test/unit/dimensions.js @@ -345,17 +345,94 @@ QUnit.test( "child of a hidden elem (or unconnected node) has accurate inner/out $divNormal.remove(); } ); -QUnit.test( "table dimensions", function( assert ) { +QUnit.test( "hidden element with dimensions from a stylesheet", function( assert ) { assert.expect( 2 ); - var table = jQuery( "<table><colgroup><col></col><col></col></colgroup><tbody><tr><td></td><td>a</td></tr><tr><td></td><td>a</td></tr></tbody></table>" ).appendTo( "#qunit-fixture" ), + var div = jQuery( "" + + "<div class='display-none-style'>" + + " <style>" + + " .display-none-style {" + + " display: none;" + + " width: 111px;" + + " height: 123px;" + + " }" + + " </style>" + + "</div>" + + "" ) + .appendTo( "#qunit-fixture" ); + + assert.strictEqual( div.width(), 111, "width of a hidden element" ); + assert.strictEqual( div.height(), 123, "height of a hidden element" ); +} ); + +QUnit.test( "hidden element with implicit content-based dimensions", function( assert ) { + assert.expect( 2 ); + + var container = jQuery( "" + + + // font-size affects the child dimensions implicitly + "<div style='font-size: 20px'>" + + " <div style='padding: 10px; display: none'>" + + " <div style='width: 3em; height: 2em'></div>" + + " </div>" + + "</div>" + + "" ), + div = container.children().first(); + + container.appendTo( "#qunit-fixture" ); + + assert.strictEqual( div.width(), 60, "width of a hidden element" ); + assert.strictEqual( div.height(), 40, "height of a hidden element" ); +} ); + +QUnit.test( "table dimensions", function( assert ) { + assert.expect( 3 ); + + var table = jQuery( "" + + "<table style='border-spacing: 0'>" + + " <colgroup>" + + " <col />" + + " <col span='2' class='col-double' />" + + " </colgroup>" + + " <tbody>" + + " <tr>" + + " <td></td>" + + " <td class='td-a-1'>a</td>" + + " <td class='td-b-1'>b</td>" + + " </tr>" + + " <tr>" + + " <td></td>" + + " <td>a</td>" + + " <td>b</td>" + + " </tr>" + + " </tbody>" + + "</table>" + ).appendTo( "#qunit-fixture" ), tdElem = table.find( "td" ).first(), - colElem = table.find( "col" ).first().width( 300 ); + colElem = table.find( "col" ).first(), + doubleColElem = table.find( ".col-double" ); - table.find( "td" ).css( { "margin": 0, "padding": 0 } ); + table.find( "td" ).css( { margin: 0, padding: 0, border: 0 } ); + + colElem.width( 300 ); + + table.find( ".td-a-1" ).width( 200 ); + table.find( ".td-b-1" ).width( 400 ); assert.equal( tdElem.width(), tdElem.width(), "width() doesn't alter dimension values of empty cells, see trac-11293" ); - assert.equal( colElem.width(), 300, "col elements have width(), see trac-12243" ); + assert.equal( colElem.width(), 300, "col elements have width(), (trac-12243)" ); + + // Support: IE 11+ + // In IE, `<col>` computed width is `"auto"` unless `width` is set + // explicitly via CSS so measurements there remain incorrect. Because of + // the lack of a proper workaround, we accept this limitation. + // To make IE pass the test, set the width explicitly. + if ( QUnit.isIE ) { + doubleColElem.width( 600 ); + } + + assert.equal( doubleColElem.width(), 600, + "col with span measured correctly (gh-5628)" ); } ); QUnit.test( "SVG dimensions (basic content-box)", function( assert ) { @@ -668,7 +745,7 @@ QUnit.test( "interaction with scrollbars (gh-3589)", function( assert ) { .appendTo( "#qunit-fixture" ), // Workarounds for IE kill fractional output here. - fraction = document.documentMode ? 0 : 0.5, + fraction = QUnit.isIE ? 0 : 0.5, borderWidth = 1, padding = 2, size = 100 + fraction, diff --git a/test/unit/event.js b/test/unit/event.js index 474699105..dac53ed93 100644 --- a/test/unit/event.js +++ b/test/unit/event.js @@ -2707,7 +2707,7 @@ testIframe( // IE does propagate the event to the parent document. In this test // we mainly care about the inner element so we'll just skip this one // assertion in IE. - if ( !document.documentMode ) { + if ( !QUnit.isIE ) { assert.ok( false, "fired a focusin event in the parent document" ); } } ); diff --git a/test/unit/support.js b/test/unit/support.js index 0961f3183..8e6fc83a7 100644 --- a/test/unit/support.js +++ b/test/unit/support.js @@ -82,26 +82,32 @@ testIframe( expectedMap = { ie_11: { cssHas: true, + reliableColDimensions: 11, reliableTrDimensions: false }, chrome: { cssHas: true, + reliableColDimensions: true, reliableTrDimensions: true }, safari: { cssHas: true, + reliableColDimensions: false, reliableTrDimensions: true }, firefox: { cssHas: true, + reliableColDimensions: false, reliableTrDimensions: false }, ios_16_3: { cssHas: false, + reliableColDimensions: false, reliableTrDimensions: true }, ios: { cssHas: true, + reliableColDimensions: false, reliableTrDimensions: true } }; @@ -113,7 +119,7 @@ testIframe( } } - if ( document.documentMode ) { + if ( QUnit.isIE ) { expected = expectedMap.ie_11; } else if ( /\b(?:headless)?chrome\//i.test( userAgent ) ) { |