css.js (14536B)
1 define( [ 2 "./core", 3 "./core/access", 4 "./core/camelCase", 5 "./core/nodeName", 6 "./var/rcssNum", 7 "./css/var/rnumnonpx", 8 "./css/var/rcustomProp", 9 "./css/var/cssExpand", 10 "./css/var/getStyles", 11 "./css/var/swap", 12 "./css/curCSS", 13 "./css/adjustCSS", 14 "./css/addGetHookIf", 15 "./css/support", 16 "./css/finalPropName", 17 18 "./core/init", 19 "./core/ready", 20 "./selector" // contains 21 ], function( jQuery, access, camelCase, nodeName, rcssNum, rnumnonpx, 22 rcustomProp, cssExpand, getStyles, swap, curCSS, adjustCSS, addGetHookIf, 23 support, finalPropName ) { 24 25 "use strict"; 26 27 var 28 29 // Swappable if display is none or starts with table 30 // except "table", "table-cell", or "table-caption" 31 // See here for display values: https://developer.mozilla.org/en-US/docs/CSS/display 32 rdisplayswap = /^(none|table(?!-c[ea]).+)/, 33 cssShow = { position: "absolute", visibility: "hidden", display: "block" }, 34 cssNormalTransform = { 35 letterSpacing: "0", 36 fontWeight: "400" 37 }; 38 39 function setPositiveNumber( _elem, value, subtract ) { 40 41 // Any relative (+/-) values have already been 42 // normalized at this point 43 var matches = rcssNum.exec( value ); 44 return matches ? 45 46 // Guard against undefined "subtract", e.g., when used as in cssHooks 47 Math.max( 0, matches[ 2 ] - ( subtract || 0 ) ) + ( matches[ 3 ] || "px" ) : 48 value; 49 } 50 51 function boxModelAdjustment( elem, dimension, box, isBorderBox, styles, computedVal ) { 52 var i = dimension === "width" ? 1 : 0, 53 extra = 0, 54 delta = 0, 55 marginDelta = 0; 56 57 // Adjustment may not be necessary 58 if ( box === ( isBorderBox ? "border" : "content" ) ) { 59 return 0; 60 } 61 62 for ( ; i < 4; i += 2 ) { 63 64 // Both box models exclude margin 65 // Count margin delta separately to only add it after scroll gutter adjustment. 66 // This is needed to make negative margins work with `outerHeight( true )` (gh-3982). 67 if ( box === "margin" ) { 68 marginDelta += jQuery.css( elem, box + cssExpand[ i ], true, styles ); 69 } 70 71 // If we get here with a content-box, we're seeking "padding" or "border" or "margin" 72 if ( !isBorderBox ) { 73 74 // Add padding 75 delta += jQuery.css( elem, "padding" + cssExpand[ i ], true, styles ); 76 77 // For "border" or "margin", add border 78 if ( box !== "padding" ) { 79 delta += jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); 80 81 // But still keep track of it otherwise 82 } else { 83 extra += jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); 84 } 85 86 // If we get here with a border-box (content + padding + border), we're seeking "content" or 87 // "padding" or "margin" 88 } else { 89 90 // For "content", subtract padding 91 if ( box === "content" ) { 92 delta -= jQuery.css( elem, "padding" + cssExpand[ i ], true, styles ); 93 } 94 95 // For "content" or "padding", subtract border 96 if ( box !== "margin" ) { 97 delta -= jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); 98 } 99 } 100 } 101 102 // Account for positive content-box scroll gutter when requested by providing computedVal 103 if ( !isBorderBox && computedVal >= 0 ) { 104 105 // offsetWidth/offsetHeight is a rounded sum of content, padding, scroll gutter, and border 106 // Assuming integer scroll gutter, subtract the rest and round down 107 delta += Math.max( 0, Math.ceil( 108 elem[ "offset" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 ) ] - 109 computedVal - 110 delta - 111 extra - 112 0.5 113 114 // If offsetWidth/offsetHeight is unknown, then we can't determine content-box scroll gutter 115 // Use an explicit zero to avoid NaN (gh-3964) 116 ) ) || 0; 117 } 118 119 return delta + marginDelta; 120 } 121 122 function getWidthOrHeight( elem, dimension, extra ) { 123 124 // Start with computed style 125 var styles = getStyles( elem ), 126 127 // To avoid forcing a reflow, only fetch boxSizing if we need it (gh-4322). 128 // Fake content-box until we know it's needed to know the true value. 129 boxSizingNeeded = !support.boxSizingReliable() || extra, 130 isBorderBox = boxSizingNeeded && 131 jQuery.css( elem, "boxSizing", false, styles ) === "border-box", 132 valueIsBorderBox = isBorderBox, 133 134 val = curCSS( elem, dimension, styles ), 135 offsetProp = "offset" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 ); 136 137 // Support: Firefox <=54 138 // Return a confounding non-pixel value or feign ignorance, as appropriate. 139 if ( rnumnonpx.test( val ) ) { 140 if ( !extra ) { 141 return val; 142 } 143 val = "auto"; 144 } 145 146 147 // Support: IE 9 - 11 only 148 // Use offsetWidth/offsetHeight for when box sizing is unreliable. 149 // In those cases, the computed value can be trusted to be border-box. 150 if ( ( !support.boxSizingReliable() && isBorderBox || 151 152 // Support: IE 10 - 11+, Edge 15 - 18+ 153 // IE/Edge misreport `getComputedStyle` of table rows with width/height 154 // set in CSS while `offset*` properties report correct values. 155 // Interestingly, in some cases IE 9 doesn't suffer from this issue. 156 !support.reliableTrDimensions() && nodeName( elem, "tr" ) || 157 158 // Fall back to offsetWidth/offsetHeight when value is "auto" 159 // This happens for inline elements with no explicit setting (gh-3571) 160 val === "auto" || 161 162 // Support: Android <=4.1 - 4.3 only 163 // Also use offsetWidth/offsetHeight for misreported inline dimensions (gh-3602) 164 !parseFloat( val ) && jQuery.css( elem, "display", false, styles ) === "inline" ) && 165 166 // Make sure the element is visible & connected 167 elem.getClientRects().length ) { 168 169 isBorderBox = jQuery.css( elem, "boxSizing", false, styles ) === "border-box"; 170 171 // Where available, offsetWidth/offsetHeight approximate border box dimensions. 172 // Where not available (e.g., SVG), assume unreliable box-sizing and interpret the 173 // retrieved value as a content box dimension. 174 valueIsBorderBox = offsetProp in elem; 175 if ( valueIsBorderBox ) { 176 val = elem[ offsetProp ]; 177 } 178 } 179 180 // Normalize "" and auto 181 val = parseFloat( val ) || 0; 182 183 // Adjust for the element's box model 184 return ( val + 185 boxModelAdjustment( 186 elem, 187 dimension, 188 extra || ( isBorderBox ? "border" : "content" ), 189 valueIsBorderBox, 190 styles, 191 192 // Provide the current computed size to request scroll gutter calculation (gh-3589) 193 val 194 ) 195 ) + "px"; 196 } 197 198 jQuery.extend( { 199 200 // Add in style property hooks for overriding the default 201 // behavior of getting and setting a style property 202 cssHooks: { 203 opacity: { 204 get: function( elem, computed ) { 205 if ( computed ) { 206 207 // We should always get a number back from opacity 208 var ret = curCSS( elem, "opacity" ); 209 return ret === "" ? "1" : ret; 210 } 211 } 212 } 213 }, 214 215 // Don't automatically add "px" to these possibly-unitless properties 216 cssNumber: { 217 animationIterationCount: true, 218 aspectRatio: true, 219 borderImageSlice: true, 220 columnCount: true, 221 flexGrow: true, 222 flexShrink: true, 223 fontWeight: true, 224 gridArea: true, 225 gridColumn: true, 226 gridColumnEnd: true, 227 gridColumnStart: true, 228 gridRow: true, 229 gridRowEnd: true, 230 gridRowStart: true, 231 lineHeight: true, 232 opacity: true, 233 order: true, 234 orphans: true, 235 scale: true, 236 widows: true, 237 zIndex: true, 238 zoom: true, 239 240 // SVG-related 241 fillOpacity: true, 242 floodOpacity: true, 243 stopOpacity: true, 244 strokeMiterlimit: true, 245 strokeOpacity: true 246 }, 247 248 // Add in properties whose names you wish to fix before 249 // setting or getting the value 250 cssProps: {}, 251 252 // Get and set the style property on a DOM Node 253 style: function( elem, name, value, extra ) { 254 255 // Don't set styles on text and comment nodes 256 if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) { 257 return; 258 } 259 260 // Make sure that we're working with the right name 261 var ret, type, hooks, 262 origName = camelCase( name ), 263 isCustomProp = rcustomProp.test( name ), 264 style = elem.style; 265 266 // Make sure that we're working with the right name. We don't 267 // want to query the value if it is a CSS custom property 268 // since they are user-defined. 269 if ( !isCustomProp ) { 270 name = finalPropName( origName ); 271 } 272 273 // Gets hook for the prefixed version, then unprefixed version 274 hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ]; 275 276 // Check if we're setting a value 277 if ( value !== undefined ) { 278 type = typeof value; 279 280 // Convert "+=" or "-=" to relative numbers (trac-7345) 281 if ( type === "string" && ( ret = rcssNum.exec( value ) ) && ret[ 1 ] ) { 282 value = adjustCSS( elem, name, ret ); 283 284 // Fixes bug trac-9237 285 type = "number"; 286 } 287 288 // Make sure that null and NaN values aren't set (trac-7116) 289 if ( value == null || value !== value ) { 290 return; 291 } 292 293 // If a number was passed in, add the unit (except for certain CSS properties) 294 // The isCustomProp check can be removed in jQuery 4.0 when we only auto-append 295 // "px" to a few hardcoded values. 296 if ( type === "number" && !isCustomProp ) { 297 value += ret && ret[ 3 ] || ( jQuery.cssNumber[ origName ] ? "" : "px" ); 298 } 299 300 // background-* props affect original clone's values 301 if ( !support.clearCloneStyle && value === "" && name.indexOf( "background" ) === 0 ) { 302 style[ name ] = "inherit"; 303 } 304 305 // If a hook was provided, use that value, otherwise just set the specified value 306 if ( !hooks || !( "set" in hooks ) || 307 ( value = hooks.set( elem, value, extra ) ) !== undefined ) { 308 309 if ( isCustomProp ) { 310 style.setProperty( name, value ); 311 } else { 312 style[ name ] = value; 313 } 314 } 315 316 } else { 317 318 // If a hook was provided get the non-computed value from there 319 if ( hooks && "get" in hooks && 320 ( ret = hooks.get( elem, false, extra ) ) !== undefined ) { 321 322 return ret; 323 } 324 325 // Otherwise just get the value from the style object 326 return style[ name ]; 327 } 328 }, 329 330 css: function( elem, name, extra, styles ) { 331 var val, num, hooks, 332 origName = camelCase( name ), 333 isCustomProp = rcustomProp.test( name ); 334 335 // Make sure that we're working with the right name. We don't 336 // want to modify the value if it is a CSS custom property 337 // since they are user-defined. 338 if ( !isCustomProp ) { 339 name = finalPropName( origName ); 340 } 341 342 // Try prefixed name followed by the unprefixed name 343 hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ]; 344 345 // If a hook was provided get the computed value from there 346 if ( hooks && "get" in hooks ) { 347 val = hooks.get( elem, true, extra ); 348 } 349 350 // Otherwise, if a way to get the computed value exists, use that 351 if ( val === undefined ) { 352 val = curCSS( elem, name, styles ); 353 } 354 355 // Convert "normal" to computed value 356 if ( val === "normal" && name in cssNormalTransform ) { 357 val = cssNormalTransform[ name ]; 358 } 359 360 // Make numeric if forced or a qualifier was provided and val looks numeric 361 if ( extra === "" || extra ) { 362 num = parseFloat( val ); 363 return extra === true || isFinite( num ) ? num || 0 : val; 364 } 365 366 return val; 367 } 368 } ); 369 370 jQuery.each( [ "height", "width" ], function( _i, dimension ) { 371 jQuery.cssHooks[ dimension ] = { 372 get: function( elem, computed, extra ) { 373 if ( computed ) { 374 375 // Certain elements can have dimension info if we invisibly show them 376 // but it must have a current display style that would benefit 377 return rdisplayswap.test( jQuery.css( elem, "display" ) ) && 378 379 // Support: Safari 8+ 380 // Table columns in Safari have non-zero offsetWidth & zero 381 // getBoundingClientRect().width unless display is changed. 382 // Support: IE <=11 only 383 // Running getBoundingClientRect on a disconnected node 384 // in IE throws an error. 385 ( !elem.getClientRects().length || !elem.getBoundingClientRect().width ) ? 386 swap( elem, cssShow, function() { 387 return getWidthOrHeight( elem, dimension, extra ); 388 } ) : 389 getWidthOrHeight( elem, dimension, extra ); 390 } 391 }, 392 393 set: function( elem, value, extra ) { 394 var matches, 395 styles = getStyles( elem ), 396 397 // Only read styles.position if the test has a chance to fail 398 // to avoid forcing a reflow. 399 scrollboxSizeBuggy = !support.scrollboxSize() && 400 styles.position === "absolute", 401 402 // To avoid forcing a reflow, only fetch boxSizing if we need it (gh-3991) 403 boxSizingNeeded = scrollboxSizeBuggy || extra, 404 isBorderBox = boxSizingNeeded && 405 jQuery.css( elem, "boxSizing", false, styles ) === "border-box", 406 subtract = extra ? 407 boxModelAdjustment( 408 elem, 409 dimension, 410 extra, 411 isBorderBox, 412 styles 413 ) : 414 0; 415 416 // Account for unreliable border-box dimensions by comparing offset* to computed and 417 // faking a content-box to get border and padding (gh-3699) 418 if ( isBorderBox && scrollboxSizeBuggy ) { 419 subtract -= Math.ceil( 420 elem[ "offset" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 ) ] - 421 parseFloat( styles[ dimension ] ) - 422 boxModelAdjustment( elem, dimension, "border", false, styles ) - 423 0.5 424 ); 425 } 426 427 // Convert to pixels if value adjustment is needed 428 if ( subtract && ( matches = rcssNum.exec( value ) ) && 429 ( matches[ 3 ] || "px" ) !== "px" ) { 430 431 elem.style[ dimension ] = value; 432 value = jQuery.css( elem, dimension ); 433 } 434 435 return setPositiveNumber( elem, value, subtract ); 436 } 437 }; 438 } ); 439 440 jQuery.cssHooks.marginLeft = addGetHookIf( support.reliableMarginLeft, 441 function( elem, computed ) { 442 if ( computed ) { 443 return ( parseFloat( curCSS( elem, "marginLeft" ) ) || 444 elem.getBoundingClientRect().left - 445 swap( elem, { marginLeft: 0 }, function() { 446 return elem.getBoundingClientRect().left; 447 } ) 448 ) + "px"; 449 } 450 } 451 ); 452 453 // These hooks are used by animate to expand properties 454 jQuery.each( { 455 margin: "", 456 padding: "", 457 border: "Width" 458 }, function( prefix, suffix ) { 459 jQuery.cssHooks[ prefix + suffix ] = { 460 expand: function( value ) { 461 var i = 0, 462 expanded = {}, 463 464 // Assumes a single number if not a string 465 parts = typeof value === "string" ? value.split( " " ) : [ value ]; 466 467 for ( ; i < 4; i++ ) { 468 expanded[ prefix + cssExpand[ i ] + suffix ] = 469 parts[ i ] || parts[ i - 2 ] || parts[ 0 ]; 470 } 471 472 return expanded; 473 } 474 }; 475 476 if ( prefix !== "margin" ) { 477 jQuery.cssHooks[ prefix + suffix ].set = setPositiveNumber; 478 } 479 } ); 480 481 jQuery.fn.extend( { 482 css: function( name, value ) { 483 return access( this, function( elem, name, value ) { 484 var styles, len, 485 map = {}, 486 i = 0; 487 488 if ( Array.isArray( name ) ) { 489 styles = getStyles( elem ); 490 len = name.length; 491 492 for ( ; i < len; i++ ) { 493 map[ name[ i ] ] = jQuery.css( elem, name[ i ], false, styles ); 494 } 495 496 return map; 497 } 498 499 return value !== undefined ? 500 jQuery.style( elem, name, value ) : 501 jQuery.css( elem, name ); 502 }, name, value, arguments.length > 1 ); 503 } 504 } ); 505 506 return jQuery; 507 } );