css.js 14 KB

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