├── .eslintrc ├── .gitignore ├── .travis.yml ├── LICENSE ├── README.md ├── bower.json ├── dist ├── ResizeObserver.global.js └── ResizeObserver.js ├── karma.conf.js ├── package-lock.json ├── package.json ├── rollup.config.js ├── src ├── ResizeObservation.js ├── ResizeObserver.js ├── ResizeObserverController.js ├── ResizeObserverEntry.js ├── ResizeObserverSPI.js ├── index.d.ts ├── index.js ├── index.js.flow ├── shims │ ├── es6-collections.js │ ├── global.js │ └── requestAnimationFrame.js └── utils │ ├── defineConfigurable.js │ ├── geometry.js │ ├── getWindowOf.js │ ├── isBrowser.js │ └── throttle.js └── tests ├── ResizeObserver.spec.js ├── ResizeObserverEntry.spec.js ├── node ├── ResizeObserver.spec.node.js └── index.js └── resources ├── helpers.js └── observer.js /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "eslint:recommended", 3 | "parser": "babel-eslint", 4 | "parserOptions": { 5 | "ecmaVersion": 2018, 6 | "sourceType": "module" 7 | }, 8 | "globals": { 9 | "DOMRectReadOnly": true 10 | }, 11 | "env": { 12 | "browser": true, 13 | "es6": true, 14 | "jasmine": true, 15 | "node": true 16 | }, 17 | "rules": { 18 | "accessor-pairs": "error", 19 | "array-bracket-spacing": ["error", "never"], 20 | "array-callback-return": "error", 21 | "arrow-spacing": ["error", {"before": true, "after": true}], 22 | "block-scoped-var": "error", 23 | "block-spacing": ["error", "never"], 24 | "brace-style": "error", 25 | "camelcase": "error", 26 | "capitalized-comments": ["error", "always", { "ignoreConsecutiveComments": true }], 27 | "comma-dangle": ["error", "never"], 28 | "comma-spacing": ["error", { "before": false, "after": true }], 29 | "comma-style": ["error", "last"], 30 | "computed-property-spacing": ["error", "never"], 31 | "consistent-return": "error", 32 | "curly": "error", 33 | "dot-notation": "error", 34 | "eol-last": "error", 35 | "eqeqeq": ["error"], 36 | "func-call-spacing": ["error", "never"], 37 | "getter-return": "error", 38 | "guard-for-in": "error", 39 | "indent": ["error", 4], 40 | "key-spacing": "error", 41 | "keyword-spacing": ["error", { "before": true }], 42 | "line-comment-position": ["error", { "position": "above" }], 43 | "lines-between-class-members": ["error", "always"], 44 | "max-depth": ["error", 2], 45 | "max-len": ["error", 120, 4], 46 | "max-nested-callbacks": ["error", 3], 47 | "new-cap": "error", 48 | "new-parens": "error", 49 | "newline-after-var": "error", 50 | "newline-before-return": "error", 51 | "no-alert": "error", 52 | "no-array-constructor": "error", 53 | "no-caller": "error", 54 | "no-catch-shadow": "error", 55 | "no-duplicate-imports": "error", 56 | "no-else-return": "error", 57 | "no-empty-function": "error", 58 | "no-eq-null": "error", 59 | "no-eval": "error", 60 | "no-extend-native": "error", 61 | "no-extra-bind": "error", 62 | "no-extra-parens": "error", 63 | "no-floating-decimal": "error", 64 | "no-implicit-globals": "error", 65 | "no-implied-eval": "error", 66 | "no-inline-comments": "error", 67 | "no-invalid-this": "error", 68 | "no-labels": "error", 69 | "no-lone-blocks": "error", 70 | "no-lonely-if": "error", 71 | "no-loop-func": "error", 72 | "no-multi-assign": "error", 73 | "no-multi-spaces": "error", 74 | "no-multi-str": "error", 75 | "no-multiple-empty-lines": ["error", {"max": 1}], 76 | "no-nested-ternary": "error", 77 | "no-new": "error", 78 | "no-new-func": "error", 79 | "no-new-object": "error", 80 | "no-new-wrappers": "error", 81 | "no-param-reassign": "error", 82 | "no-proto": "error", 83 | "no-return-assign": "error", 84 | "no-self-compare": "error", 85 | "no-shadow": "error", 86 | "no-throw-literal": "error", 87 | "no-trailing-spaces": "error", 88 | "no-undef-init": "error", 89 | "no-undefined": "error", 90 | "no-unmodified-loop-condition": "error", 91 | "no-unneeded-ternary": "error", 92 | "no-unused-expressions": ["error", { "allowTernary": true }], 93 | "no-use-before-define": ["error", "nofunc"], 94 | "no-useless-call": "error", 95 | "no-useless-computed-key": "error", 96 | "no-useless-concat": "error", 97 | "no-useless-constructor": "error", 98 | "no-useless-rename": "error", 99 | "no-useless-return": "error", 100 | "no-var": "error", 101 | "no-void": "error", 102 | "no-whitespace-before-property": "error", 103 | "no-with": "error", 104 | "object-curly-spacing": ["error", "never"], 105 | "object-shorthand": ["error", "always"], 106 | "one-var": ["error", { "var": "always", "let": "always", "const": "never" }], 107 | "operator-assignment": ["error", "always"], 108 | "operator-linebreak": ["error", "after"], 109 | "padded-blocks": ["error", "never"], 110 | "prefer-arrow-callback": "error", 111 | "prefer-const": "error", 112 | "prefer-destructuring": "error", 113 | "prefer-spread": "error", 114 | "quote-props": ["error", "as-needed"], 115 | "quotes": ["error", "single"], 116 | "radix": "error", 117 | "require-await": "error", 118 | "rest-spread-spacing": ["error", "never"], 119 | "semi": ["error", "always"], 120 | "semi-spacing": "error", 121 | "sort-imports": "error", 122 | "space-before-blocks": "error", 123 | "space-before-function-paren": ["error", { "anonymous": "always", "named": "never" }], 124 | "space-in-parens": ["error", "never"], 125 | "space-infix-ops": "error", 126 | "space-unary-ops": "error", 127 | "strict": "error", 128 | "template-curly-spacing": ["error", "always"], 129 | "vars-on-top": "error", 130 | "wrap-iife": ["error", "inside"], 131 | "yoda": "error", 132 | 133 | "require-jsdoc": ["error", { 134 | "require": { 135 | "FunctionDeclaration": true, 136 | "MethodDefinition": true, 137 | "ClassDeclaration": false 138 | } 139 | }], 140 | 141 | "valid-jsdoc": ["error", { 142 | "prefer": { 143 | "return": "returns" 144 | }, 145 | "preferType": { 146 | "String": "string", 147 | "Number": "number", 148 | "Boolean": "boolean" 149 | }, 150 | "requireReturn": true, 151 | "requireParamDescription": false, 152 | "requireReturnType": true, 153 | "requireReturnDescription": false, 154 | "matchDescription": ".+" 155 | }], 156 | 157 | 158 | "lines-around-comment": [ 159 | "error", 160 | { 161 | "beforeBlockComment": true, 162 | "allowBlockStart": true 163 | } 164 | ] 165 | } 166 | } 167 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /node_modules 2 | /dist/ResizeObserver.es.js 3 | /dist/ResizeObserver.js.flow 4 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | 3 | language: node_js 4 | 5 | node_js: 6 | - "node" 7 | 8 | addons: 9 | firefox: 10 | "latest" 11 | 12 | before_script: 13 | - export DISPLAY=:99.0 14 | - sh -e /etc/init.d/xvfb start 15 | 16 | script: 17 | - 'if [ "$TRAVIS_PULL_REQUEST" = "false" ]; then npm run test:ci; fi' 18 | - 'if [ "$TRAVIS_PULL_REQUEST" != "false" ]; then npm run test:ci:pull; fi' 19 | 20 | env: 21 | global: 22 | - secure: GL+U+eGM/0dZftjRsq9iEjkJCXQrRSif3yVXGeZW44r+LR8om4bXOBi/FpVfdw5SjOBrE4dwYLdQpVlHVc17Uqv1wYuauzGz5dQjNvNOlZtxVJhOLS2hDsU0mltWPV3zHNf75lsQ+bKQfWfkJ2DJLNAfZGVIchnkhguLjNKYfR2WGt0XLulCFUqB1ugfYOpxWk3BYjCP+QlqS0B2jsmgkEqLeYo6I/XXWwOta8ZAXgmaKrUrFQC5EGrD3KiHJFoxcc37twgvJJOMchvIGV9GLjCOJoeoJXjMi/Cpq3+jeTdw1PKb9kRbvZ8hteGKbtu8SmCInevHJwwEa4Ip2Gy0ksi80RVFamioEckh1drMbWp520qRpgytrwopYdwzyJ2D7m2Wowh3Uf7RopEOQ2NzvPL+8toVN6kXX47vfU13Xa16am14uAP6c5beQ4Ad1TIgFic1x7E7BKHvuJl+nU4w16HNV+jSTc+ePPZku+yaWrQCfJFLcKuKB1Ft9cDSaRlasgLKGVNJJKo6tLNV8AGu2CbOU8YjlTQ5Ak4fCFBe+0jXOM/gCvFCGaAobV4mUn4pi0g/bmVFEOY8lw0Z4175q3KWyNJe1nhVoMNoiN3bbwGR5Qt3ydWkTuK5RJGaFMMAS3FeWwu589bNB11G6v0Lzm+/vgzbASbc295Ar2ycYwY= 23 | - secure: m+yqQRYYyruzZgDqzu9mJNDmAPEKzcnE6Yp8+qkCTtfrEpa0Lc4TGuIi+feTYxcLLV9parb10j/bhn9ZpTJvnH18tNQxQP+GqVdkRWbnPaY+1gwaBXdhzw4uEOXec7vG8eGPjua4I26nM47yHWnS+PvROLE+odUgaCSIp5qZcyuhsxALljuLSnW3kHyXgAv5Qyott0NlpiPchCM0QnFaZuPyZ76VoxQM5xw4bMlXc9LTql+DCisJ0ZvvNmPrFRNXPXKTEAkvWGolr7g8cOZTW33+5DO7VdRxtbLV12lx5QMyl6DArpQvo3MuKHcnijr3SQgP/ocIgc+dRHHXeSTWrZWcBXPpSjkDYsWw6p+F+WYyAs2FQ39HZ4aLrzPDPtyKizPWCuzWXONOb21lyibZ41vPyjuWiEypY/wtVkjDMWAoRVwZpYFW0dKY4h4gJntRSRo1szAteuqLDZ2MUguCv77oDtuXaZF0wBiDKfxqEbeexhZ0ky/6cMCO8Af2qsyFcIr/2Vz0n7BkPW6/z4xjzFDjwUBGomt2ex4ANERQuu8qhqloq2d3xqAPUCi6kz3IuSDhFju5ouTR8BwNbhXCJm+5PYpP4V39vzaR+Bd4FTetT78xLPlSj6gyyA7mI7ZCMR5TTFSr8vPCowAB6yk3SiOTACupHRCIdA4hqkE4eSY= 24 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Denis Rul 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ResizeObserver Polyfill 2 | ============= 3 | 4 | [![Build Status][travis-image]][travis-url] 5 | 6 | 7 | A polyfill for the Resize Observer API. 8 | 9 | Implementation is based on the MutationObserver and uses Mutation Events as a fall back if the first one is not supported, so there will be no polling unless DOM changes. Doesn't modify observed elements. Handles CSS transitions/animations and can possibly observe changes caused by dynamic CSS pseudo-classes, e.g. by `:hover`. 10 | 11 | Follows the [spec](http://rawgit.com/WICG/ResizeObserver/master/index.html) and the native implementation. The size is _2.44 KiB_ when minified and gzipped. 12 | 13 | [Live demo](http://que-etc.github.io/resize-observer-polyfill) (has style problems in IE10 and lower). 14 | 15 | ## Installation 16 | 17 | From NPM: 18 | 19 | ```sh 20 | npm install resize-observer-polyfill --save-dev 21 | ``` 22 | 23 | ~~From Bower:~~ (will be removed with the next major release) 24 | 25 | ```sh 26 | bower install resize-observer-polyfill --save-dev 27 | ``` 28 | 29 | 30 | ## Browser Support 31 | 32 | Polyfill has been tested in the following browsers: 33 | 34 | [![Build Status](https://saucelabs.com/browser-matrix/que-etc.svg)](https://saucelabs.com/beta/builds/303f5344a7214ba5b62bc7079a15d376) 35 | 36 | **NOTE:** Internet Explorer 8 and its earlier versions are not supported. 37 | 38 | ## Usage Example 39 | 40 | It's recommended to use this library in the form of a [ponyfill](https://github.com/sindresorhus/ponyfill), which doesn't inflict modifications of the global object. 41 | 42 | ```javascript 43 | import ResizeObserver from 'resize-observer-polyfill'; 44 | 45 | const ro = new ResizeObserver((entries, observer) => { 46 | for (const entry of entries) { 47 | const {left, top, width, height} = entry.contentRect; 48 | 49 | console.log('Element:', entry.target); 50 | console.log(`Element's size: ${ width }px x ${ height }px`); 51 | console.log(`Element's paddings: ${ top }px ; ${ left }px`); 52 | } 53 | }); 54 | 55 | ro.observe(document.body); 56 | ``` 57 | 58 | Package's main file is a ES5 [UMD](https://github.com/umdjs/umd) bundle that will be swapped with the ES6 modules version for those bundlers that are aware of the [module](https://github.com/rollup/rollup/wiki/pkg.module) field, e.g. for [Rollup](https://github.com/rollup/rollup) or webpack 2+. 59 | 60 | **Note**: global version of the polyfill (`dist/ResizeObserver.global`) is deprecated and will be removed in the next major release. 61 | 62 | ## Observation Strategy 63 | 64 | As mentioned above, this implementation primarily (but not solely) relies on Mutation Observer with a fallback to Mutation Events for IE 9 and IE 10. 65 | 66 | Speaking of Mutation Events as a fallback approach: they might not be as ugly as they are being rendered, particularly when their calls are batched, throttled and there is no need to analyze changes. Given that, they won't interrupt browser's reflow/repaint cycles (same for MutationObserver) and may even outperform Internet Explorer's implementation of MO causing little to no performance degradation. In contemporary browsers (Chrome, Firefox, etc.) Mutation Observer slows down [the suite](https://jsfiddle.net/que_etc/gaqLe8rn/) that includes 200 iterations of adding/removing elements, changing attributes and modifying text data by less than 1%. Internet Explorer gives different results with MO slowing down the same suite by 2-3% while Mutation Events show the difference of ~0.6%. 67 | 68 | As for the reasons why other approaches, namely the iframe/object and `scroll` strategies, were ruled out: 69 | * They require the observed element to be non-statically positioned. 70 | * You can't apply them directly to quite a number of elements: ``, ``, `