css.js 13 KB

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