get-size.js 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250
  1. /*!
  2. * getSize v1.2.2
  3. * measure size of elements
  4. * MIT license
  5. */
  6. /*jshint browser: true, strict: true, undef: true, unused: true */
  7. /*global define: false, exports: false, require: false, module: false, console: false */
  8. ( function( window, undefined ) {
  9. 'use strict';
  10. // -------------------------- helpers -------------------------- //
  11. // get a number from a string, not a percentage
  12. function getStyleSize( value ) {
  13. var num = parseFloat( value );
  14. // not a percent like '100%', and a number
  15. var isValid = value.indexOf('%') === -1 && !isNaN( num );
  16. return isValid && num;
  17. }
  18. function noop() {}
  19. var logError = typeof console === 'undefined' ? noop :
  20. function( message ) {
  21. console.error( message );
  22. };
  23. // -------------------------- measurements -------------------------- //
  24. var measurements = [
  25. 'paddingLeft',
  26. 'paddingRight',
  27. 'paddingTop',
  28. 'paddingBottom',
  29. 'marginLeft',
  30. 'marginRight',
  31. 'marginTop',
  32. 'marginBottom',
  33. 'borderLeftWidth',
  34. 'borderRightWidth',
  35. 'borderTopWidth',
  36. 'borderBottomWidth'
  37. ];
  38. function getZeroSize() {
  39. var size = {
  40. width: 0,
  41. height: 0,
  42. innerWidth: 0,
  43. innerHeight: 0,
  44. outerWidth: 0,
  45. outerHeight: 0
  46. };
  47. for ( var i=0, len = measurements.length; i < len; i++ ) {
  48. var measurement = measurements[i];
  49. size[ measurement ] = 0;
  50. }
  51. return size;
  52. }
  53. function defineGetSize( getStyleProperty ) {
  54. // -------------------------- setup -------------------------- //
  55. var isSetup = false;
  56. var getStyle, boxSizingProp, isBoxSizeOuter;
  57. /**
  58. * setup vars and functions
  59. * do it on initial getSize(), rather than on script load
  60. * For Firefox bug https://bugzilla.mozilla.org/show_bug.cgi?id=548397
  61. */
  62. function setup() {
  63. // setup once
  64. if ( isSetup ) {
  65. return;
  66. }
  67. isSetup = true;
  68. var getComputedStyle = window.getComputedStyle;
  69. getStyle = ( function() {
  70. var getStyleFn = getComputedStyle ?
  71. function( elem ) {
  72. return getComputedStyle( elem, null );
  73. } :
  74. function( elem ) {
  75. return elem.currentStyle;
  76. };
  77. return function getStyle( elem ) {
  78. var style = getStyleFn( elem );
  79. if ( !style ) {
  80. logError( 'Style returned ' + style +
  81. '. Are you running this code in a hidden iframe on Firefox? ' +
  82. 'See http://bit.ly/getsizebug1' );
  83. }
  84. return style;
  85. };
  86. })();
  87. // -------------------------- box sizing -------------------------- //
  88. boxSizingProp = getStyleProperty('boxSizing');
  89. /**
  90. * WebKit measures the outer-width on style.width on border-box elems
  91. * IE & Firefox measures the inner-width
  92. */
  93. if ( boxSizingProp ) {
  94. var div = document.createElement('div');
  95. div.style.width = '200px';
  96. div.style.padding = '1px 2px 3px 4px';
  97. div.style.borderStyle = 'solid';
  98. div.style.borderWidth = '1px 2px 3px 4px';
  99. div.style[ boxSizingProp ] = 'border-box';
  100. var body = document.body || document.documentElement;
  101. body.appendChild( div );
  102. var style = getStyle( div );
  103. isBoxSizeOuter = getStyleSize( style.width ) === 200;
  104. body.removeChild( div );
  105. }
  106. }
  107. // -------------------------- getSize -------------------------- //
  108. function getSize( elem ) {
  109. setup();
  110. // use querySeletor if elem is string
  111. if ( typeof elem === 'string' ) {
  112. elem = document.querySelector( elem );
  113. }
  114. // do not proceed on non-objects
  115. if ( !elem || typeof elem !== 'object' || !elem.nodeType ) {
  116. return;
  117. }
  118. var style = getStyle( elem );
  119. // if hidden, everything is 0
  120. if ( style.display === 'none' ) {
  121. return getZeroSize();
  122. }
  123. var size = {};
  124. size.width = elem.offsetWidth;
  125. size.height = elem.offsetHeight;
  126. var isBorderBox = size.isBorderBox = !!( boxSizingProp &&
  127. style[ boxSizingProp ] && style[ boxSizingProp ] === 'border-box' );
  128. // get all measurements
  129. for ( var i=0, len = measurements.length; i < len; i++ ) {
  130. var measurement = measurements[i];
  131. var value = style[ measurement ];
  132. value = mungeNonPixel( elem, value );
  133. var num = parseFloat( value );
  134. // any 'auto', 'medium' value will be 0
  135. size[ measurement ] = !isNaN( num ) ? num : 0;
  136. }
  137. var paddingWidth = size.paddingLeft + size.paddingRight;
  138. var paddingHeight = size.paddingTop + size.paddingBottom;
  139. var marginWidth = size.marginLeft + size.marginRight;
  140. var marginHeight = size.marginTop + size.marginBottom;
  141. var borderWidth = size.borderLeftWidth + size.borderRightWidth;
  142. var borderHeight = size.borderTopWidth + size.borderBottomWidth;
  143. var isBorderBoxSizeOuter = isBorderBox && isBoxSizeOuter;
  144. // overwrite width and height if we can get it from style
  145. var styleWidth = getStyleSize( style.width );
  146. if ( styleWidth !== false ) {
  147. size.width = styleWidth +
  148. // add padding and border unless it's already including it
  149. ( isBorderBoxSizeOuter ? 0 : paddingWidth + borderWidth );
  150. }
  151. var styleHeight = getStyleSize( style.height );
  152. if ( styleHeight !== false ) {
  153. size.height = styleHeight +
  154. // add padding and border unless it's already including it
  155. ( isBorderBoxSizeOuter ? 0 : paddingHeight + borderHeight );
  156. }
  157. size.innerWidth = size.width - ( paddingWidth + borderWidth );
  158. size.innerHeight = size.height - ( paddingHeight + borderHeight );
  159. size.outerWidth = size.width + marginWidth;
  160. size.outerHeight = size.height + marginHeight;
  161. return size;
  162. }
  163. // IE8 returns percent values, not pixels
  164. // taken from jQuery's curCSS
  165. function mungeNonPixel( elem, value ) {
  166. // IE8 and has percent value
  167. if ( window.getComputedStyle || value.indexOf('%') === -1 ) {
  168. return value;
  169. }
  170. var style = elem.style;
  171. // Remember the original values
  172. var left = style.left;
  173. var rs = elem.runtimeStyle;
  174. var rsLeft = rs && rs.left;
  175. // Put in the new values to get a computed value out
  176. if ( rsLeft ) {
  177. rs.left = elem.currentStyle.left;
  178. }
  179. style.left = value;
  180. value = style.pixelLeft;
  181. // Revert the changed values
  182. style.left = left;
  183. if ( rsLeft ) {
  184. rs.left = rsLeft;
  185. }
  186. return value;
  187. }
  188. return getSize;
  189. }
  190. // transport
  191. if ( typeof define === 'function' && define.amd ) {
  192. // AMD for RequireJS
  193. define( [ 'get-style-property/get-style-property' ], defineGetSize );
  194. } else if ( typeof exports === 'object' ) {
  195. // CommonJS for Component
  196. module.exports = defineGetSize( require('desandro-get-style-property') );
  197. } else {
  198. // browser global
  199. window.getSize = defineGetSize( window.getStyleProperty );
  200. }
  201. })( window );