├── .gitignore ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── bower.json ├── demo.gif ├── dist ├── progressively.min.css └── progressively.min.js ├── docs ├── favicon.ico ├── index.html ├── progressively.min.css └── progressively.min.js ├── package.json └── src ├── progressively.css └── progressively.js /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .vscode 3 | 4 | # Logs 5 | logs 6 | *.log 7 | npm-debug.log* 8 | yarn-debug.log* 9 | yarn-error.log* 10 | 11 | # Runtime data 12 | pids 13 | *.pid 14 | *.seed 15 | *.pid.lock 16 | 17 | # Directory for instrumented libs generated by jscoverage/JSCover 18 | lib-cov 19 | 20 | # Coverage directory used by tools like istanbul 21 | coverage 22 | 23 | # nyc test coverage 24 | .nyc_output 25 | 26 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 27 | .grunt 28 | 29 | # Bower dependency directory (https://bower.io/) 30 | bower_components 31 | 32 | # node-waf configuration 33 | .lock-wscript 34 | 35 | # Compiled binary addons (http://nodejs.org/api/addons.html) 36 | build/Release 37 | 38 | # Dependency directories 39 | node_modules/ 40 | jspm_packages/ 41 | 42 | # Typescript v1 declaration files 43 | typings/ 44 | 45 | # Optional npm cache directory 46 | .npm 47 | 48 | # Optional eslint cache 49 | .eslintcache 50 | 51 | # Optional REPL history 52 | .node_repl_history 53 | 54 | # Output of 'npm pack' 55 | *.tgz 56 | 57 | # Yarn Integrity file 58 | .yarn-integrity 59 | 60 | # dotenv environment variables file 61 | .env 62 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to progressively 2 | First off, thanks for taking the time to contribute! 3 | 4 | Now, take a moment to be sure your contributions make sense to everyone else. 5 | These are just guidelines, not rules. 6 | Use your best judgment, and feel free to propose changes to this document in a pull request. 7 | 8 | ## Reporting Issues 9 | Found a problem? Want a new feature? First of all see if your issue or idea has [already been reported](../../issues). 10 | If don't, just open a [new clear and descriptive issue](../../issues/new). 11 | 12 | ## Submitting pull requests 13 | Pull requests are the greatest contributions, so be sure they are focused in scope, and do avoid unrelated commits. 14 | - Fork it! 15 | - Clone your fork: `git clone https://github.com//progressively` 16 | - Navigate to the newly cloned directory: `cd progressively` 17 | - Create a new branch for the new feature: `git checkout -b my-new-feature` 18 | - Install the tools necessary for development: `npm install` 19 | - Make your changes. 20 | - Commit your changes: `git commit -am 'Add some feature'` 21 | - Push to the branch: `git push origin my-new-feature` 22 | - Submit a pull request with full remarks documenting your changes. 23 | 24 | ## Testing 25 | Every time you write a test, remember to answer all the questions: 26 | 27 | 1. What are you testing? 28 | 2. What should it do? 29 | 3. What is the actual output? 30 | 4. What is the expected output? 31 | 5. How can the test be reproduced? 32 | 33 | ## Code Style 34 | Follows the [JavaScript Standard Style](http://standardjs.com/). 35 | 36 | ## Scripts 37 | - `npm run lint`: lint the files. 38 | - `npm run build:css`: minify and add vendor prefixes (if needed) the css file. 39 | - `npm run build:js`: uglify the js file. 40 | 41 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016 Ashish 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 | # Progressively 2 | 3 | [![Travis](https://img.shields.io/travis/thinker3197/progressively.svg)](https://travis-ci.org/thinker3197/progressively) 4 | [![Coveralls](https://img.shields.io/coveralls/thinker3197/progressively.svg)](https://coveralls.io/github/thinker3197/progressively?branch=master) 5 | [![npm (scoped)](https://img.shields.io/npm/v/progressively.svg)](https://www.npmjs.com/package/progressively) 6 | [![David](https://img.shields.io/david/thinker3197/progressively.svg)](https://david-dm.org/thinker3197/progressively) 7 | [![Standard - JavaScript Style Guide](https://img.shields.io/badge/code%20style-standard-brightgreen.svg)](http://standardjs.com/) 8 | 9 | > A JavaScript library to load images progressively 10 | 11 | It’s written entirely in JavaScript so it doesn’t depend on 3rd-party libraries like jQuery. It's super small, < 1.2kB when minified & gzipped! It will load the full-size images only when the user browses to that part of the page, saving bandwidth & server requests. It is compatible with all modern browsers. See the [Demo](https://thinker3197.github.io/progressively). 12 | 13 | ![demo-image](https://raw.githubusercontent.com/thinker3197/progressively/master/demo.gif) 14 | 15 | ## Table of Contents 16 | 17 | - [Install](#install) 18 | - [Usage](#usage) 19 | - [API](#api) 20 | - [Contribute](#contribute) 21 | - [License](#license) 22 | 23 | ## Install 24 | 25 | This project uses [node](http://nodejs.org) and [npm](https://npmjs.com). Go check them out if you don't have them locally installed. 26 | 27 | ```sh 28 | $ npm install --save progressively 29 | ``` 30 | 31 | Alternatively you can use [Bower](https://bower.io/). 32 | 33 | ```sh 34 | $ bower install progressively 35 | ``` 36 | 37 | With a module bundler like [rollup](http://rollupjs.org/) or [webpack](https://webpack.js.org/), use as you would anything else: 38 | 39 | ```javascript 40 | // using ES6 modules 41 | import progressively from 'progressively' 42 | 43 | // using CommonJS modules 44 | var progressively = require('progressively') 45 | ``` 46 | 47 | The [UMD](https://github.com/umdjs/umd) build is also available on CDN: 48 | 49 | ```html 50 | 51 | 52 | 53 | ``` 54 | Once loaded, you can access the library on `window.progressively`. 55 | 56 | You also need to embed the css file at your page 57 | 58 | ```html 59 | 60 | 61 | 62 | ``` 63 | 64 | ## Usage 65 | 66 | Add a image to your `HTML` file setting the `src` attribute containing the lower quality image (< 20kb for ideal cases) and the `data-progressive` attribute holding the path/url to the high quality image. 67 | 68 | You can use [lowly](https://github.com/thiamsantos/lowly) to create the images in low quality. Just run `npm i -g lowly` and then `lowly image.jpg`, after that a new image `image-lowly.jpg` will be created in the same directory of source image. 69 | 70 | ```html 71 |
72 | 73 |
74 | ``` 75 | 76 | And initiate the script. 77 | 78 | ```js 79 | progressively.init() 80 | ``` 81 | 82 | See [demo](https://thinker3197.github.io/progressively) for examples. 83 | 84 | ### Use medium quality images for mobile devices 85 | 86 | You can add a medium resolution image via `data-progressive-sm` to reduce the filesize on mobile devices with small screens. The default breakpoint for loading `progressive-sm` image is `600` (in device independent pixels). Progressively will load the `data-progressive-sm` image when the user's device width is less than `smBreakpoint` value. 87 | 88 | ```html 89 |
90 | 91 |
92 | ``` 93 | 94 | ### Use as bg-image 95 | 96 | You can also use progressively for background-images. Simply use `progressive__bg` instead of `progressive__img`: 97 | 98 | ```html 99 |
100 | ``` 101 | 102 | ## API 103 | 104 | ### progressively.init(options) 105 | 106 | The `init()` API has a few options 107 | 108 | #### throttle 109 | Type: `Number` Default: `300` 110 | 111 | The `throttle` is managed by an internal function that prevents performance issues from continuous firing of `window.onscroll` events. Using a throttle will set a small timeout when the user scrolls and will keep throttling until the user stops. The default is 300 milliseconds. 112 | 113 | #### delay 114 | Type: `Number` Default: `100` value 115 | 116 | The `delay` function sets the timout value for images to start load asynchronously. Ideally it's value should be low. 117 | 118 | #### smBreakpoint 119 | Type: `Number` Default: `600` value 120 | 121 | The `loadImage` function uses this value, to load images in a medium quality (if defined and if the user's viewport is smaller than smBreakpoint). 122 | 123 | #### onLoadComplete 124 | Type: `Function` Arguments: `None` 125 | 126 | The `onLoadComplete` function is callback function which executes when all images have loaded. It is fired when all the image elements have the `*--is-loaded` class. 127 | 128 | #### onLoad 129 | Type: `Function` Arguments: `HTMLElement` 130 | 131 | The `onLoad` function is invoked whenever an image elements finishes loading. It accepts `HTMLElement` as an argument which is the current element that is loaded. 132 | 133 | ```js 134 | progressively.init({ 135 | delay: 50, 136 | throttle: 300, 137 | smBreakpoint: 600, 138 | onLoad: function(elem) { 139 | console.log(elem); 140 | }, 141 | onLoadComplete: function() { 142 | console.log('All images have finished loading!'); 143 | } 144 | }); 145 | ``` 146 | 147 | ### progressively.render() 148 | 149 | Progressively has a `render()` method that can be used to make progressively poll your images when you're not scrolling. For instance in some case you want to render your images before/widthout scrolling down to the image, you can use `render`. 150 | 151 | ## Contribute 152 | See the [contributing file](CONTRIBUTING.md) for instructions. 153 | 154 | ## License 155 | [MIT license](LICENSE) © [Ashish](https://thinker3197.github.io/) 156 | -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "progressively", 3 | "description": "A JavaScript library to load images progressively", 4 | "main": "./src/progressively.js", 5 | "authors": [ 6 | "Ashish" 7 | ], 8 | "license": "MIT", 9 | "keywords": [ 10 | "progressive", 11 | "lazy-load", 12 | "images" 13 | ], 14 | "homepage": "https://github.com/thinker3197/progressively" 15 | } 16 | -------------------------------------------------------------------------------- /demo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinker3197/progressively/9aea32f73bb27828b1c3a7832bfb3035d52c0c60/demo.gif -------------------------------------------------------------------------------- /dist/progressively.min.css: -------------------------------------------------------------------------------- 1 | .progressive{overflow:hidden;position:relative;background:#efefef}.progressive__img{width:100%;height:100%;transform:translateZ(0)}.progressive--not-loaded{filter:blur(30px);transform:scale(1.1)}.progressive--is-loaded{filter:blur(20px);animation:a .5s both;transform:scale(1)}@keyframes a{0%{filter:blur(20px)}to{filter:blur(0)}} -------------------------------------------------------------------------------- /dist/progressively.min.js: -------------------------------------------------------------------------------- 1 | !function(e,t){"function"==typeof define&&define.amd?define(function(){return t(e)}):"object"==typeof exports?module.exports=t:e.progressively=t(e)}(this,function(e){"use strict";function t(e,t){var n={};for(var o in e)n[o]=t.hasOwnProperty(o)?t[o]:e[o];return n}function n(e){var t=e.getBoundingClientRect(),n=t.top,o=t.height;e=e.parentNode;do{if(t=e.getBoundingClientRect(),!(n<=t.bottom))return!1;if(n+o<=t.top)return!1;e=e.parentNode}while(e!==document.body&&e!==document);return n<=document.documentElement.clientHeight}function o(e,t){setTimeout(function(){var n=new Image;n.onload=function(){e.classList.remove("progressive--not-loaded"),e.classList.add("progressive--is-loaded"),e.classList.contains("progressive__bg")?e.style["background-image"]='url("'+this.src+'")':e.src=this.src,d(e)},r()<=t.smBreakpoint&&e.getAttribute("data-progressive-sm")?(e.classList.add("progressive--loaded-sm"),n.src=e.getAttribute("data-progressive-sm")):(e.classList.remove("progressive--loaded-sm"),n.src=e.getAttribute("data-progressive"))},t.delay)}function r(){return Math.max(document.documentElement.clientWidth,window.innerWidth||0)}function i(){c||(clearTimeout(c),c=setTimeout(function(){l.check(),l.render(),c=null},s.throttle))}var s,c,d,a,l={};return d=function(){},s={throttle:300,delay:100,onLoadComplete:function(){},onLoad:function(){},smBreakpoint:600},l.init=function(n){n=n||{},s=t(s,n),d=s.onLoad||d,a=[].slice.call(document.querySelectorAll(".progressive__img, .progressive__bg")),l.render(),document.addEventListener?(e.addEventListener("scroll",i,!1),e.addEventListener("resize",i,!1),e.addEventListener("load",i,!1)):(e.attachEvent("onscroll",i),e.attachEvent("onresize",i),e.attachEvent("onload",i))},l.render=function(){for(var e,t=a.length-1;t>=0;--t)e=a[t],n(e)&&e.classList.contains("progressive--not-loaded")&&(o(e,s),a.splice(t,1));this.check()},l.check=function(){a.length||(s.onLoadComplete(),this.drop())},l.drop=function(){document.removeEventListener?(e.removeEventListener("scroll",i),e.removeEventListener("resize",i)):(e.detachEvent("onscroll",i),e.detachEvent("onresize",i)),clearTimeout(c)},l}); -------------------------------------------------------------------------------- /docs/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinker3197/progressively/9aea32f73bb27828b1c3a7832bfb3035d52c0c60/docs/favicon.ico -------------------------------------------------------------------------------- /docs/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | Progressively - Load Images progressively 13 | 14 | 15 | 16 | 17 | 18 | 205 | 206 | 207 | 208 |
209 | Fork me on GitHub 210 |
211 |
212 |
213 |

Progressively

214 |

A JavaScript library to load images progressively.

215 |
216 |
217 |
218 |

Progressively is a javascript library for loading images progressively. It’s written entirely in JavaScript so it doesn’t depend on 3rd-party libraries like jQuery. It's super small, 219 | < 1.2kB when minified & gzipped! It will load images on when user browse to the page, saving bandwidth & server requests. 220 |

221 |

Usage & Api

222 |
    223 |
  • 224 |

    Installation

    225 | bower install progressively 226 |
    227 |

    OR

    228 | npm install progressively 229 |
  • 230 |
  • 231 |

    Add Files

    232 | <link rel="stylesheet" src="progressively.min.css"> 233 |
    234 |
    235 | <script type="text/javascript" src="progressively.min.js"> 236 |
  • 237 |
  • 238 |

    Initialize

    239 | progressively.init(options); 240 |
  • 241 |
  • 242 |

    .init() (options)

    243 |

    The init() API takes a few options

    244 |

    throttle

    245 |

    Type: Number, Default: 300

    246 |

    The throttle is managed by an internal function that prevents performance issues from continuous firing of window.onscroll events. Using a throttle will set a small timeout when the user scrolls and will keep throttling until the user stops. The default is 300 milliseconds.

    247 |

    delay

    248 |

    Type: Number, Default: 100

    249 |

    The delay function sets the timout value for images to start load asynchronously. Ideally it's value should be low.

    250 |

    onLoad

    251 |

    Type: Function, Arguments: HTMLElement

    252 |

    The imgload function is invoked whenever an image elements finishes loading. It accepts HTMLElement as an argument which is the current element that is loaded.

    253 |

    onLoadComplete

    254 |

    Type: Function, Arguments: None

    255 |

    The afterload function is callback function which executes when all images have loaded. It is fired when all the image elements have the *--is-loaded class.

    256 |
  • 257 |
258 |
259 | Download 260 |
261 |
262 |
263 |
264 | 265 |
266 |
267 | 268 |
269 |
270 | 271 |
272 |
273 | 274 |
275 |
276 | 277 |
278 |
279 | 280 |
281 |
282 | 285 | 286 | 293 | 294 | 295 | 296 | -------------------------------------------------------------------------------- /docs/progressively.min.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * progressively 1.1.2 3 | * https://github.com/thinker3197/progressively 4 | * @license MIT licensed 5 | * 6 | * Copyright (C) 2016-17 Ashish 7 | */.progressive{overflow:hidden;position:relative;background:#efefef}.progressive__img{width:100%;height:100%;transform:translateZ(0)}.progressive--not-loaded{filter:blur(30px);transform:scale(1.1)}.progressive--is-loaded{filter:blur(20px);animation:a .5s both;transform:scale(1)}@keyframes a{0%{filter:blur(20px)}to{filter:blur(0)}} -------------------------------------------------------------------------------- /docs/progressively.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * progressively 1.1.2 3 | * https://github.com/thinker3197/progressively 4 | * @license MIT licensed 5 | * 6 | * Copyright (C) 2016-17 Ashish 7 | */!function(e,t){"function"==typeof define&&define.amd?define(function(){return t(e)}):"object"==typeof exports?module.exports=t:e.progressively=t(e)}(this,function(e){"use strict";function t(e,t){var n={};for(var o in e)n[o]=t.hasOwnProperty(o)?t[o]:e[o];return n}function n(e){var t=e.getBoundingClientRect(),n=t.top,o=t.height;e=e.parentNode;do{if(t=e.getBoundingClientRect(),!(n<=t.bottom))return!1;if(n+o<=t.top)return!1;e=e.parentNode}while(e!==document.body&&e!==document);return n<=document.documentElement.clientHeight}function o(e,t){setTimeout(function(){var n=new Image;n.onload=function(){e.classList.remove("progressive--not-loaded"),e.classList.add("progressive--is-loaded"),e.classList.contains("progressive__bg")?e.style["background-image"]='url("'+this.src+'")':e.src=this.src,d(e)},r()<=t.smBreakpoint&&e.getAttribute("data-progressive-sm")?(e.classList.add("progressive--loaded-sm"),n.src=e.getAttribute("data-progressive-sm")):(e.classList.remove("progressive--loaded-sm"),n.src=e.getAttribute("data-progressive"))},t.delay)}function r(){return Math.max(document.documentElement.clientWidth,window.innerWidth||0)}function i(){c||(clearTimeout(c),c=setTimeout(function(){l.check(),l.render(),c=null},s.throttle))}var s,c,d,a,l={};return d=function(){},s={throttle:300,delay:100,onLoadComplete:function(){},onLoad:function(){},smBreakpoint:600},l.init=function(n){n=n||{},s=t(s,n),d=s.onLoad||d,a=[].slice.call(document.querySelectorAll(".progressive__img, .progressive__bg")),l.render(),document.addEventListener?(e.addEventListener("scroll",i,!1),e.addEventListener("resize",i,!1),e.addEventListener("load",i,!1)):(e.attachEvent("onscroll",i),e.attachEvent("onresize",i),e.attachEvent("onload",i))},l.render=function(){for(var e,t=a.length-1;t>=0;--t)e=a[t],n(e)&&e.classList.contains("progressive--not-loaded")&&(o(e,s),a.splice(t,1));this.check()},l.check=function(){a.length||(s.onLoadComplete(),this.drop())},l.drop=function(){document.removeEventListener?(e.removeEventListener("scroll",i),e.removeEventListener("resize",i)):(e.detachEvent("onscroll",i),e.detachEvent("onresize",i)),clearTimeout(c)},l}); -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "progressively", 3 | "version": "1.2.5", 4 | "description": "A JavaScript library to load images progressively", 5 | "main": "dist/progressively.min.js", 6 | "scripts": { 7 | "lint": "standard \"src/**/*.js\"", 8 | "build:css": "cssnano src/progressively.css dist/progressively.min.css", 9 | "build:js": "uglifyjs src/progressively.js -cm -o dist/progressively.min.js" 10 | }, 11 | "repository": { 12 | "type": "git", 13 | "url": "git+https://github.com/thinker3197/progressively.git" 14 | }, 15 | "keywords": [ 16 | "progressive", 17 | "lazy-load", 18 | "images" 19 | ], 20 | "author": "Ashish", 21 | "license": "MIT", 22 | "bugs": { 23 | "url": "https://github.com/thinker3197/progressively/issues" 24 | }, 25 | "homepage": "https://github.com/thinker3197/progressively/blob/master/README.md", 26 | "devDependencies": { 27 | "cssnano-cli": "^1.0.5", 28 | "standard": "^8.6.0", 29 | "uglify-js": "^3.0.11" 30 | }, 31 | "standard": { 32 | "globals": [ 33 | "define", 34 | "Image" 35 | ] 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/progressively.css: -------------------------------------------------------------------------------- 1 | /* 2 | * progressively 1.1.2 3 | * https://github.com/thinker3197/progressively 4 | * @license MIT licensed 5 | * 6 | * Copyright (C) 2016-17 Ashish 7 | */ 8 | 9 | .progressive { 10 | overflow: hidden; 11 | position: relative; 12 | background: #efefef; 13 | } 14 | 15 | .progressive__img { 16 | width: 100%; 17 | height: 100%; 18 | transform: translateZ(0); 19 | } 20 | 21 | .progressive--not-loaded { 22 | filter: blur(30px); 23 | transform: scale(1.1); 24 | } 25 | 26 | .progressive--is-loaded { 27 | filter: blur(20px); 28 | animation: sharpen 0.5s both; 29 | transform: scale(1); 30 | } 31 | 32 | @keyframes sharpen { 33 | from { 34 | filter: blur(20px); 35 | } 36 | to { 37 | filter: blur(0px); 38 | } 39 | } -------------------------------------------------------------------------------- /src/progressively.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * progressively 1.1.3 3 | * https://github.com/thinker3197/progressively 4 | * @license MIT licensed 5 | * 6 | * Copyright (C) 2016-17 Ashish 7 | */ 8 | 9 | ; 10 | (function (root, factory) { 11 | if (typeof define === 'function' && define.amd) { 12 | define(function () { 13 | return factory(root) 14 | }) 15 | } else if (typeof exports === 'object') { 16 | module.exports = factory 17 | } else { 18 | root.progressively = factory(root) 19 | } 20 | })(this, function (root) { 21 | 'use strict' 22 | 23 | var progressively = {} 24 | 25 | var defaults, poll, onLoad, inodes 26 | 27 | onLoad = function () {} 28 | 29 | function extend (primaryObject, secondaryObject) { 30 | var o = {} 31 | for (var prop in primaryObject) { 32 | o[prop] = secondaryObject.hasOwnProperty(prop) ? secondaryObject[prop] : primaryObject[prop] 33 | } 34 | return o 35 | } 36 | 37 | /** 38 | * Check if element is currently visible 39 | * @param object DOMElement 40 | * @return boolean 41 | */ 42 | function inView (el) { 43 | var box = el.getBoundingClientRect() 44 | var top = box.top 45 | var height = box.height 46 | 47 | el = el.parentNode 48 | 49 | do { 50 | box = el.getBoundingClientRect() 51 | 52 | if (!(top <= box.bottom)) { 53 | return false 54 | } 55 | if ((top + height) <= box.top) { 56 | return false 57 | } 58 | 59 | el = el.parentNode 60 | } while (el !== document.body && el !== document) 61 | 62 | return top <= document.documentElement.clientHeight 63 | } 64 | 65 | /** 66 | * Load image and add loaded-class. Loads the minified version, if small display 67 | * @param object DOMElement 68 | * @param object defaults 69 | * @return boolean true, if fully loaded; false, if minified version was loaded 70 | */ 71 | function loadImage (el, defaults) { 72 | setTimeout(function () { 73 | var img = new Image() 74 | 75 | img.onload = function () { 76 | el.classList.remove('progressive--not-loaded') 77 | el.classList.add('progressive--is-loaded') 78 | 79 | if (el.classList.contains('progressive__bg')) { 80 | // Load image as css-background-image 81 | el.style['background-image'] = 'url("' + this.src + '")' 82 | } else { 83 | el.src = this.src 84 | } 85 | 86 | onLoad(el) 87 | } 88 | 89 | // Load minified version, if viewport-width is smaller than defaults.smBreakpoint: 90 | if (getClientWidth() <= defaults.smBreakpoint && el.getAttribute('data-progressive-sm')) { 91 | el.classList.add('progressive--loaded-sm') 92 | img.src = el.getAttribute('data-progressive-sm') 93 | } else { 94 | el.classList.remove('progressive--loaded-sm') 95 | img.src = el.getAttribute('data-progressive') 96 | } 97 | }, defaults.delay) 98 | } 99 | 100 | /** 101 | * Returns the width of the client's viewport 102 | * @return integer client-width 103 | */ 104 | function getClientWidth () { 105 | return Math.max(document.documentElement.clientWidth, window.innerWidth || 0) 106 | } 107 | 108 | /** 109 | * Listens to an event, and throttles 110 | */ 111 | function listen () { 112 | if (poll) { 113 | return 114 | } 115 | clearTimeout(poll) 116 | poll = setTimeout(function () { 117 | progressively.check() 118 | progressively.render() 119 | poll = null 120 | }, defaults.throttle) 121 | } 122 | 123 | /* 124 | * default settings 125 | */ 126 | defaults = { 127 | throttle: 300, // appropriate value, don't change unless intended 128 | delay: 100, 129 | onLoadComplete: function () {}, 130 | onLoad: function () {}, 131 | smBreakpoint: 600 132 | } 133 | 134 | /** 135 | * Initializer. Finds image-elements and adds listeners. 136 | * @param object options 137 | */ 138 | progressively.init = function (options) { 139 | options = options || {} 140 | 141 | defaults = extend(defaults, options) 142 | 143 | onLoad = defaults.onLoad || onLoad 144 | 145 | inodes = [].slice.call(document.querySelectorAll('.progressive__img, .progressive__bg')) 146 | 147 | progressively.render() 148 | 149 | if (document.addEventListener) { 150 | root.addEventListener('scroll', listen, false) 151 | root.addEventListener('resize', listen, false) 152 | root.addEventListener('load', listen, false) 153 | } else { 154 | root.attachEvent('onscroll', listen) 155 | root.attachEvent('onresize', listen) 156 | root.attachEvent('onload', listen) 157 | } 158 | } 159 | 160 | /** 161 | * Loads necessary images in small or full quality. 162 | */ 163 | progressively.render = function () { 164 | var elem 165 | 166 | for (var i = inodes.length - 1; i >= 0; --i) { 167 | elem = inodes[i] 168 | 169 | if (inView(elem) && elem.classList.contains('progressive--not-loaded')) { 170 | loadImage(elem, defaults) 171 | 172 | inodes.splice(i, 1) 173 | } 174 | } 175 | 176 | this.check() 177 | } 178 | 179 | /** 180 | * Check if all images are loaded in full quality, then drop. 181 | */ 182 | progressively.check = function () { 183 | if (!inodes.length) { 184 | defaults.onLoadComplete() 185 | this.drop() 186 | } 187 | } 188 | 189 | /** 190 | * Drops progressively-listeners 191 | */ 192 | progressively.drop = function () { 193 | if (document.removeEventListener) { 194 | root.removeEventListener('scroll', listen) 195 | root.removeEventListener('resize', listen) 196 | } else { 197 | root.detachEvent('onscroll', listen) 198 | root.detachEvent('onresize', listen) 199 | } 200 | clearTimeout(poll) 201 | } 202 | 203 | return progressively 204 | }) 205 | --------------------------------------------------------------------------------