├── .editorconfig ├── .github └── ISSUE_TEMPLATE │ ├── bug_report.md │ ├── feature_request.md │ ├── other-issues.md │ └── question.md ├── .gitignore ├── .npmignore ├── BingSiteAuth.xml ├── CHANGELOG.md ├── Gruntfile.js ├── LICENSE ├── README.md ├── animate.html ├── assets ├── css │ ├── bootstrap-theme.css │ ├── bootstrap-theme.min.css │ ├── bootstrap.css │ ├── bootstrap.min.css │ ├── carousel.css │ └── tidy.css ├── imgs │ └── loader.gif └── js │ ├── bootstrap.js │ └── bootstrap.min.js ├── bower.json ├── component.json ├── index.html ├── lazysizes-umd.js ├── lazysizes-umd.min.js ├── lazysizes.d.ts ├── lazysizes.js ├── lazysizes.min.js ├── no-src.html ├── optimumx ├── child.html ├── index.html └── js │ └── parent.js ├── package-lock.json ├── package.json ├── plugins ├── README.md ├── artdirect │ ├── README.md │ ├── ls.artdirect.js │ └── ls.artdirect.min.js ├── aspectratio │ ├── README.md │ ├── ls.aspectratio.js │ └── ls.aspectratio.min.js ├── attrchange │ ├── README.md │ ├── ls.attrchange.js │ └── ls.attrchange.min.js ├── bgset │ ├── README.md │ ├── ls.bgset.js │ └── ls.bgset.min.js ├── blur-up │ ├── README.md │ ├── ls.blur-up.js │ └── ls.blur-up.min.js ├── custommedia │ ├── README.md │ ├── ls.custommedia.js │ └── ls.custommedia.min.js ├── fix-edge-h-descriptor │ ├── README.md │ ├── ls.fix-edge-h-descriptor.js │ └── ls.fix-edge-h-descriptor.min.js ├── fix-ios-sizes │ ├── fix-ios-sizes.js │ └── fix-ios-sizes.min.js ├── include │ ├── README.md │ ├── ls.include.js │ └── ls.include.min.js ├── native-loading │ ├── README.md │ ├── ls.native-loading.js │ └── ls.native-loading.min.js ├── noscript │ ├── README.md │ ├── ls.noscript.js │ └── ls.noscript.min.js ├── object-fit │ ├── README.md │ ├── ls.object-fit.js │ └── ls.object-fit.min.js ├── optimumx │ ├── README.md │ ├── ls.optimumx.js │ └── ls.optimumx.min.js ├── parent-fit │ ├── README.md │ ├── ls.parent-fit.js │ └── ls.parent-fit.min.js ├── print │ ├── README.md │ ├── ls.print.js │ └── ls.print.min.js ├── progressive │ ├── README.md │ ├── ls.progressive.js │ └── ls.progressive.min.js ├── respimg │ ├── README.md │ ├── ls.respimg.js │ └── ls.respimg.min.js ├── rias │ ├── README.md │ ├── ls.rias.js │ └── ls.rias.min.js ├── static-gecko-picture │ ├── ls.static-gecko-picture.js │ └── ls.static-gecko-picture.min.js ├── twitter │ ├── ls.twitter.js │ └── ls.twitter.min.js ├── unload │ ├── README.md │ ├── ls.unload.js │ └── ls.unload.min.js ├── unveilhooks │ ├── README.md │ ├── ls.unveilhooks.js │ └── ls.unveilhooks.min.js └── video-embed │ ├── README.md │ ├── ls.video-embed.js │ └── ls.video-embed.min.js ├── rias └── index.html ├── src ├── common.wrapper ├── lazysizes-core.js ├── lazysizes-intersection.js └── umd.wrapper ├── tests ├── functional-tests-plugins.js ├── functional-tests.js ├── index.html ├── test-files │ ├── content-file.html │ └── matchMedia.js └── test-helper.js ├── tsconfig.json └── types ├── global.d.ts └── lazysizes-config.d.ts /.editorconfig: -------------------------------------------------------------------------------- 1 | # editorconfig.org 2 | 3 | # top-most EditorConfig file 4 | root = true 5 | 6 | [*] 7 | end_of_line = lf 8 | indent_style = tab 9 | indent_size = 4 10 | charset = utf-8 11 | trim_trailing_whitespace = true 12 | insert_final_newline = true 13 | 14 | [*.json] 15 | indent_size = 2 16 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: bug 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A short, clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Provide a url where the bug can be reproduced. (Use for example: [jsbin](https://jsbin.com), [codepen](https://codepen.io), [jsfiddle.net](https://jsfiddle.net) or [codesandbox.io](https://codesandbox.io) 15 | 16 | **Steps to reproduce the behavior:** 17 | Provide all necessary steps to reproduce the bug. 18 | 19 | **What is the expected behavior:** 20 | 21 | 22 | **What happened instead:** 23 | 24 | 25 | **In what environment (browser/device etc.) does this bug happen/not happen:** 26 | 27 | **Keywords help others to find this issue:** 28 | 29 | ⚠️ Search for existing open/closed issues/discussions before you report the issue. 30 | ⚠️ If you do not provide enough information to reproduce your bug. We won't be able to work on the issue. In most cases just providing a fraction of your code is not enough! 31 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | 22 | ⚠️ Consider that most features can be solved by the simple plugin architecture and that most features doesn't need to be added to the core. 23 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/other-issues.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Other issues 3 | about: If the other templates don't fit... 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | ⚠️ Search for existing open/closed issues/discussions before you open your issue. 11 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/question.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Question 3 | about: Ask questions about the API and integration 4 | title: '' 5 | labels: question 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe your problem/question** 11 | A complete but concise description of your problem and how you are trying to fix it and where you are struggling. 12 | 13 | **Make it reproduce-able** 14 | If your problem is with code or the expected answer should include code provide a live code example using https://jsbin.com/ or https://codesandbox.io/. 15 | 16 | **Add tags/keywords** 17 | Make sure others can find your problem. 18 | 19 | ⚠️ Search for existing open/closed issues/discussions before you ask your question. 20 | ⚠️ I work on my spare time on helping users out. This means make it easy for me to simply see your live problem and help to fix it. 21 | 🤘 No panic: Don't be afraid to ask a question. 22 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.bak 2 | *.zip 3 | .* 4 | /play 5 | node_modules 6 | bower_components 7 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | *.bak 2 | *.zip 3 | .* 4 | /play 5 | node_modules 6 | bower_components 7 | /test 8 | /tests 9 | /maxdpr 10 | /rias 11 | /optimumx 12 | /assets 13 | /include 14 | /plato-report 15 | /src 16 | index.html 17 | no-src.html 18 | user-developer-experience.html 19 | animate.html 20 | Gruntfile.js 21 | component.json 22 | bower.json 23 | Authors.txt 24 | -------------------------------------------------------------------------------- /BingSiteAuth.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | D45AA4276907D8A86808F0D7C84BC7BC 4 | -------------------------------------------------------------------------------- /Gruntfile.js: -------------------------------------------------------------------------------- 1 | /*global module:true*/ 2 | (function () { 3 | "use strict"; 4 | 5 | var pkg; 6 | 7 | module.exports = function (grunt) { 8 | 9 | // Project configuration. 10 | grunt.initConfig({ 11 | // Metadata. 12 | pkg: pkg = grunt.file.readJSON("package.json"), 13 | banner: "/*! <%= pkg.name %> - v<%= pkg.version %> */\n", 14 | // Task configuration. 15 | uglify: { 16 | options: { 17 | banner: "<%= banner %>", 18 | 19 | compress: { 20 | dead_code: true 21 | } 22 | }, 23 | plugins: { 24 | files: [ 25 | { 26 | expand: true, 27 | cwd: 'plugins/', 28 | src: ['**/*.js', '!*.min.js', '!**/*.min.js'], 29 | dest: 'plugins/', 30 | ext: '.min.js', 31 | extDot: 'last' 32 | }, 33 | { 34 | expand: true, 35 | cwd: '', 36 | src: ['lazysizes*.js', '!*.min.js'], 37 | dest: '', 38 | ext: '.min.js', 39 | extDot: 'last' 40 | } 41 | ] 42 | } 43 | }, 44 | jshint: { 45 | all: { 46 | options: { 47 | jshintrc: true 48 | }, 49 | src: [ "lazysizes.js", "plugins/**/*.js", "!*.min.js", "!plugins/**/*.min.js" ] //, "Gruntfile.js", "tests/*.js" 50 | } 51 | }, 52 | qunit: { 53 | all: ['tests/*.html'] 54 | }, 55 | watch: { 56 | gruntfile: { 57 | files: [ "Gruntfile.js", "lazysizes.js" ], 58 | tasks: [ "default" ] 59 | } 60 | }, 61 | bytesize: { 62 | all: { 63 | src: [ "lazysizes.min.js" ] 64 | } 65 | }, 66 | uncss: { 67 | dist: { 68 | files: { 69 | 'assets/css/tidy.css': ['index.html', 'maxdpr/*.html'] 70 | } 71 | } 72 | }, 73 | maxFilesize: { 74 | options: { 75 | // Task-specific options go here. 76 | }, 77 | minified: { 78 | options: { 79 | maxBytes: (1024 * 7.8) 80 | }, 81 | src: ["lazysizes.min.js"] 82 | } 83 | } 84 | }); 85 | 86 | // These plugins provide necessary tasks. 87 | grunt.loadNpmTasks("grunt-contrib-jshint"); 88 | grunt.loadNpmTasks("grunt-contrib-uglify"); 89 | grunt.loadNpmTasks("grunt-contrib-watch"); 90 | grunt.loadNpmTasks('grunt-uncss'); 91 | grunt.loadNpmTasks('grunt-bytesize'); 92 | grunt.loadNpmTasks('grunt-max-filesize'); 93 | grunt.loadNpmTasks('grunt-contrib-qunit'); 94 | 95 | grunt.registerTask('wrapcore', 'wraps lazysizes into umd and common wrapper.', function() { 96 | var ls = grunt.file.read('src/lazysizes-core.js'); 97 | var common = grunt.file.read('src/common.wrapper'); 98 | var umd = grunt.file.read('src/umd.wrapper'); 99 | 100 | grunt.file.write('lazysizes.js', common.replace('{{ls}}', ls)); 101 | grunt.file.write('lazysizes-umd.js', umd.replace('{{ls}}', ls)); 102 | }); 103 | 104 | grunt.registerTask('importTs', 'import global typescript.', function() { 105 | const fileName = './lazysizes.d.ts'; 106 | const importStr = `import './types/global';\n\n`; 107 | const tsContent = grunt.file.read(fileName); 108 | 109 | grunt.file.write(fileName, importStr + tsContent); 110 | }); 111 | 112 | 113 | // Default task. 114 | grunt.registerTask("default", [ "wrapcore", "test", "uglify", "bytesize", "maxFilesize" ]); 115 | grunt.registerTask("test", [ "jshint" ]); 116 | }; 117 | })(); 118 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Alexander Farkas 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 | 23 | -------------------------------------------------------------------------------- /assets/css/carousel.css: -------------------------------------------------------------------------------- 1 | 2 | .carousel-inner > .item > img, 3 | .carousel-inner > .item > a > img { 4 | display: block; 5 | width: 100% \9; 6 | max-width: 100%; 7 | height: auto; 8 | } 9 | .carousel { 10 | position: relative; 11 | } 12 | .carousel-inner { 13 | position: relative; 14 | overflow: hidden; 15 | width: 100%; 16 | } 17 | .carousel-inner > .item { 18 | display: none; 19 | position: relative; 20 | -webkit-transition: 0.6s ease-in-out left; 21 | -o-transition: 0.6s ease-in-out left; 22 | transition: 0.6s ease-in-out left; 23 | } 24 | .carousel-inner > .item > img, 25 | .carousel-inner > .item > a > img { 26 | line-height: 1; 27 | } 28 | .carousel-inner > .active, 29 | .carousel-inner > .next, 30 | .carousel-inner > .prev { 31 | display: block; 32 | } 33 | .carousel-inner > .active { 34 | left: 0; 35 | } 36 | .carousel-inner > .next, 37 | .carousel-inner > .prev { 38 | position: absolute; 39 | top: 0; 40 | width: 100%; 41 | } 42 | .carousel-inner > .next { 43 | left: 100%; 44 | } 45 | .carousel-inner > .prev { 46 | left: -100%; 47 | } 48 | .carousel-inner > .next.left, 49 | .carousel-inner > .prev.right { 50 | left: 0; 51 | } 52 | .carousel-inner > .active.left { 53 | left: -100%; 54 | } 55 | .carousel-inner > .active.right { 56 | left: 100%; 57 | } 58 | .carousel-control { 59 | position: absolute; 60 | top: 0; 61 | left: 0; 62 | bottom: 0; 63 | width: 15%; 64 | opacity: 0.5; 65 | filter: alpha(opacity=50); 66 | font-size: 20px; 67 | color: #ffffff; 68 | text-align: center; 69 | text-shadow: 0 1px 2px rgba(0, 0, 0, 0.6); 70 | } 71 | .carousel-control.left { 72 | background-image: -webkit-linear-gradient(left, rgba(0, 0, 0, 0.5) 0%, rgba(0, 0, 0, 0.0001) 100%); 73 | background-image: -o-linear-gradient(left, rgba(0, 0, 0, 0.5) 0%, rgba(0, 0, 0, 0.0001) 100%); 74 | background-image: linear-gradient(to right, rgba(0, 0, 0, 0.5) 0%, rgba(0, 0, 0, 0.0001) 100%); 75 | background-repeat: repeat-x; 76 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#80000000', endColorstr='#00000000', GradientType=1); 77 | } 78 | .carousel-control.right { 79 | left: auto; 80 | right: 0; 81 | background-image: -webkit-linear-gradient(left, rgba(0, 0, 0, 0.0001) 0%, rgba(0, 0, 0, 0.5) 100%); 82 | background-image: -o-linear-gradient(left, rgba(0, 0, 0, 0.0001) 0%, rgba(0, 0, 0, 0.5) 100%); 83 | background-image: linear-gradient(to right, rgba(0, 0, 0, 0.0001) 0%, rgba(0, 0, 0, 0.5) 100%); 84 | background-repeat: repeat-x; 85 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000', endColorstr='#80000000', GradientType=1); 86 | } 87 | .carousel-control:hover, 88 | .carousel-control:focus { 89 | outline: 0; 90 | color: #ffffff; 91 | text-decoration: none; 92 | opacity: 0.9; 93 | filter: alpha(opacity=90); 94 | } 95 | .carousel-control .icon-prev, 96 | .carousel-control .icon-next, 97 | .carousel-control .glyphicon-chevron-left, 98 | .carousel-control .glyphicon-chevron-right { 99 | position: absolute; 100 | top: 50%; 101 | z-index: 5; 102 | display: inline-block; 103 | } 104 | .carousel-control .icon-prev, 105 | .carousel-control .glyphicon-chevron-left { 106 | left: 50%; 107 | margin-left: -10px; 108 | } 109 | .carousel-control .icon-next, 110 | .carousel-control .glyphicon-chevron-right { 111 | right: 50%; 112 | margin-right: -10px; 113 | } 114 | .carousel-control .icon-prev, 115 | .carousel-control .icon-next { 116 | width: 20px; 117 | height: 20px; 118 | margin-top: -10px; 119 | font-family: serif; 120 | } 121 | .carousel-control .icon-prev:before { 122 | content: '\2039'; 123 | } 124 | .carousel-control .icon-next:before { 125 | content: '\203a'; 126 | } 127 | .carousel-indicators { 128 | position: absolute; 129 | bottom: 10px; 130 | left: 50%; 131 | z-index: 15; 132 | width: 60%; 133 | margin-left: -30%; 134 | padding-left: 0; 135 | list-style: none; 136 | text-align: center; 137 | } 138 | .carousel-indicators li { 139 | display: inline-block; 140 | width: 10px; 141 | height: 10px; 142 | margin: 1px; 143 | text-indent: -999px; 144 | border: 1px solid #ffffff; 145 | border-radius: 10px; 146 | cursor: pointer; 147 | background-color: #000 \9; 148 | background-color: rgba(0, 0, 0, 0); 149 | } 150 | .carousel-indicators .active { 151 | margin: 0; 152 | width: 12px; 153 | height: 12px; 154 | background-color: #ffffff; 155 | } 156 | .carousel-caption { 157 | position: absolute; 158 | left: 15%; 159 | right: 15%; 160 | bottom: 20px; 161 | z-index: 10; 162 | padding-top: 20px; 163 | padding-bottom: 20px; 164 | color: #ffffff; 165 | text-align: center; 166 | text-shadow: 0 1px 2px rgba(0, 0, 0, 0.6); 167 | } 168 | .carousel-caption .btn { 169 | text-shadow: none; 170 | } 171 | @media screen and (min-width: 768px) { 172 | .carousel-control .glyphicon-chevron-left, 173 | .carousel-control .glyphicon-chevron-right, 174 | .carousel-control .icon-prev, 175 | .carousel-control .icon-next { 176 | width: 30px; 177 | height: 30px; 178 | margin-top: -15px; 179 | font-size: 30px; 180 | } 181 | .carousel-control .glyphicon-chevron-left, 182 | .carousel-control .icon-prev { 183 | margin-left: -15px; 184 | } 185 | .carousel-control .glyphicon-chevron-right, 186 | .carousel-control .icon-next { 187 | margin-right: -15px; 188 | } 189 | .carousel-caption { 190 | left: 20%; 191 | right: 20%; 192 | padding-bottom: 30px; 193 | } 194 | .carousel-indicators { 195 | bottom: 20px; 196 | } 197 | } 198 | -------------------------------------------------------------------------------- /assets/imgs/loader.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aFarkas/lazysizes/1523a4ff4579e170355c7607f445689b43229caf/assets/imgs/loader.gif -------------------------------------------------------------------------------- /assets/js/bootstrap.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * Bootstrap v3.2.0 (http://getbootstrap.com) 3 | * Copyright 2011-2014 Twitter, Inc. 4 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 5 | */ 6 | 7 | /*! 8 | * Generated using the Bootstrap Customizer (http://getbootstrap.com/customize/?id=43210ccffbad43b37f66) 9 | * Config saved to config.json and https://gist.github.com/43210ccffbad43b37f66 10 | */ 11 | if("undefined"==typeof jQuery)throw new Error("Bootstrap's JavaScript requires jQuery");+function(t){"use strict";function e(e){return this.each(function(){var n=t(this),s=n.data("bs.carousel"),r=t.extend({},i.DEFAULTS,n.data(),"object"==typeof e&&e),a="string"==typeof e?e:r.slide;s||n.data("bs.carousel",s=new i(this,r)),"number"==typeof e?s.to(e):a?s[a]():r.interval&&s.pause().cycle()})}var i=function(e,i){this.$element=t(e).on("keydown.bs.carousel",t.proxy(this.keydown,this)),this.$indicators=this.$element.find(".carousel-indicators"),this.options=i,this.paused=this.sliding=this.interval=this.$active=this.$items=null,"hover"==this.options.pause&&this.$element.on("mouseenter.bs.carousel",t.proxy(this.pause,this)).on("mouseleave.bs.carousel",t.proxy(this.cycle,this))};i.VERSION="3.2.0",i.DEFAULTS={interval:5e3,pause:"hover",wrap:!0},i.prototype.keydown=function(t){switch(t.which){case 37:this.prev();break;case 39:this.next();break;default:return}t.preventDefault()},i.prototype.cycle=function(e){return e||(this.paused=!1),this.interval&&clearInterval(this.interval),this.options.interval&&!this.paused&&(this.interval=setInterval(t.proxy(this.next,this),this.options.interval)),this},i.prototype.getItemIndex=function(t){return this.$items=t.parent().children(".item"),this.$items.index(t||this.$active)},i.prototype.to=function(e){var i=this,n=this.getItemIndex(this.$active=this.$element.find(".item.active"));return e>this.$items.length-1||0>e?void 0:this.sliding?this.$element.one("slid.bs.carousel",function(){i.to(e)}):n==e?this.pause().cycle():this.slide(e>n?"next":"prev",t(this.$items[e]))},i.prototype.pause=function(e){return e||(this.paused=!0),this.$element.find(".next, .prev").length&&t.support.transition&&(this.$element.trigger(t.support.transition.end),this.cycle(!0)),this.interval=clearInterval(this.interval),this},i.prototype.next=function(){return this.sliding?void 0:this.slide("next")},i.prototype.prev=function(){return this.sliding?void 0:this.slide("prev")},i.prototype.slide=function(e,i){var n=this.$element.find(".item.active"),s=i||n[e](),r=this.interval,a="next"==e?"left":"right",o="next"==e?"first":"last",l=this;if(!s.length){if(!this.options.wrap)return;s=this.$element.find(".item")[o]()}if(s.hasClass("active"))return this.sliding=!1;var d=s[0],h=t.Event("slide.bs.carousel",{relatedTarget:d,direction:a});if(this.$element.trigger(h),!h.isDefaultPrevented()){if(this.sliding=!0,r&&this.pause(),this.$indicators.length){this.$indicators.find(".active").removeClass("active");var u=t(this.$indicators.children()[this.getItemIndex(s)]);u&&u.addClass("active")}var c=t.Event("slid.bs.carousel",{relatedTarget:d,direction:a});return t.support.transition&&this.$element.hasClass("slide")?(s.addClass(e),s[0].offsetWidth,n.addClass(a),s.addClass(a),n.one("bsTransitionEnd",function(){s.removeClass([e,a].join(" ")).addClass("active"),n.removeClass(["active",a].join(" ")),l.sliding=!1,setTimeout(function(){l.$element.trigger(c)},0)}).emulateTransitionEnd(1e3*n.css("transition-duration").slice(0,-1))):(n.removeClass("active"),s.addClass("active"),this.sliding=!1,this.$element.trigger(c)),r&&this.cycle(),this}};var n=t.fn.carousel;t.fn.carousel=e,t.fn.carousel.Constructor=i,t.fn.carousel.noConflict=function(){return t.fn.carousel=n,this},t(document).on("click.bs.carousel.data-api","[data-slide], [data-slide-to]",function(i){var n,s=t(this),r=t(s.attr("data-target")||(n=s.attr("href"))&&n.replace(/.*(?=#[^\s]+$)/,""));if(r.hasClass("carousel")){var a=t.extend({},r.data(),s.data()),o=s.attr("data-slide-to");o&&(a.interval=!1),e.call(r,a),o&&r.data("bs.carousel").to(o),i.preventDefault()}}),t(window).on("load",function(){t('[data-ride="carousel"]').each(function(){var i=t(this);e.call(i,i.data())})})}(jQuery),+function(t){"use strict";function e(){var t=document.createElement("bootstrap"),e={WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"oTransitionEnd otransitionend",transition:"transitionend"};for(var i in e)if(void 0!==t.style[i])return{end:e[i]};return!1}t.fn.emulateTransitionEnd=function(e){var i=!1,n=this;t(this).one("bsTransitionEnd",function(){i=!0});var s=function(){i||t(n).trigger(t.support.transition.end)};return setTimeout(s,e),this},t(function(){t.support.transition=e(),t.support.transition&&(t.event.special.bsTransitionEnd={bindType:t.support.transition.end,delegateType:t.support.transition.end,handle:function(e){return t(e.target).is(this)?e.handleObj.handler.apply(this,arguments):void 0}})})}(jQuery); -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "lazysizes", 3 | "repo": "afarkas/lazysizes", 4 | "main": "lazysizes.js", 5 | "scripts": [ 6 | "lazysizes.js", 7 | "lazysizes.min.js" 8 | ], 9 | "license": "MIT", 10 | "authors": [ 11 | "Alexander Farkas " 12 | ], 13 | "moduleType": [ 14 | "amd", 15 | "globals" 16 | ], 17 | "description": "High performance (jankfree) lazy loader for images (including responsive images), iframes and scripts (widgets).", 18 | "keywords": ["lazy", "lazyloader", "performance", "responsive", "image", "responsive images", "picture", "srcset"], 19 | "ignore": [ 20 | "**/.*", 21 | "node_modules", 22 | "/assets", 23 | "/maxdpr", 24 | "/rias", 25 | "/include", 26 | "/optimumx", 27 | "bower_components", 28 | "/test", 29 | "/tests", 30 | "index.html", 31 | "no-src.html", 32 | "animate.html", 33 | "Gruntfile.js", 34 | "component.json", 35 | "package.json", 36 | "plato-report" 37 | ] 38 | } 39 | -------------------------------------------------------------------------------- /component.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "lazysizes", 3 | "version": "1.4.0", 4 | "repo": "afarkas/lazysizes", 5 | "main": "lazysizes.min.js", 6 | "scripts": ["lazysizes.min.js"], 7 | "description": "High performance (jankfree) lazy loader for images (including responsive images), iframes and scripts (widgets).", 8 | "keywords": ["lazy", "lazyloader", "performance", "responsive", "image", "responsive images", "picture", "srcset"], 9 | "license": "MIT" 10 | } 11 | -------------------------------------------------------------------------------- /lazysizes.d.ts: -------------------------------------------------------------------------------- 1 | import './types/global'; 2 | 3 | export = lazySizes; 4 | declare var lazySizes: { 5 | init: () => void; 6 | /** 7 | * @type { LazySizesConfigPartial } 8 | */ 9 | cfg: LazySizesConfigPartial; 10 | /** 11 | * @type { true } 12 | */ 13 | noSupport: true; 14 | autoSizer?: undefined; 15 | loader?: undefined; 16 | uP?: undefined; 17 | aC?: undefined; 18 | rC?: undefined; 19 | hC?: undefined; 20 | fire?: undefined; 21 | gW?: undefined; 22 | rAF?: undefined; 23 | } | { 24 | /** 25 | * @type { LazySizesConfigPartial } 26 | */ 27 | cfg: LazySizesConfigPartial; 28 | autoSizer: { 29 | _: () => void; 30 | checkElems: () => void; 31 | updateElem: (elem: Element, dataAttr: any, width?: number) => void; 32 | }; 33 | loader: { 34 | _: () => void; 35 | checkElems: (isPriority: any) => void; 36 | unveil: (elem: Element) => void; 37 | _aLSL: () => void; 38 | }; 39 | init: () => void; 40 | uP: (el: any, full: any) => void; 41 | aC: (ele: Element, cls: string) => void; 42 | rC: (ele: Element, cls: string) => void; 43 | hC: (ele: Element, cls: string) => any; 44 | fire: (elem: Element, name: string, detail: any, noBubbles: boolean, noCancelable: boolean) => CustomEvent; 45 | gW: (elem: Element, parent: Element, width?: number) => number; 46 | rAF: { 47 | (fn: any, queue: any, ...args: any[]): void; 48 | _lsFlush: () => void; 49 | }; 50 | /** 51 | * @type { true } 52 | */ 53 | noSupport?: undefined; 54 | }; 55 | declare namespace lazySizes { 56 | export { LazySizesConfigPartial }; 57 | } 58 | type LazySizesConfigPartial = { 59 | [x: string]: any; 60 | lazyClass?: string; 61 | loadedClass?: string; 62 | loadingClass?: string; 63 | preloadClass?: string; 64 | errorClass?: string; 65 | autosizesClass?: string; 66 | fastLoadedClass?: string; 67 | iframeLoadMode?: 0 | 1; 68 | srcAttr?: string; 69 | srcsetAttr?: string; 70 | sizesAttr?: string; 71 | preloadAfterLoad?: boolean; 72 | minSize?: number; 73 | customMedia?: Record; 74 | init?: boolean; 75 | expFactor?: number; 76 | hFac?: number; 77 | loadMode?: 0 | 1 | 2 | 3; 78 | loadHidden?: boolean; 79 | ricTimeout?: number; 80 | throttleDelay?: number; 81 | }; 82 | -------------------------------------------------------------------------------- /lazysizes.min.js: -------------------------------------------------------------------------------- 1 | /*! lazysizes - v5.3.2 */ 2 | 3 | !function(e){var t=function(u,D,f){"use strict";var k,H;if(function(){var e;var t={lazyClass:"lazyload",loadedClass:"lazyloaded",loadingClass:"lazyloading",preloadClass:"lazypreload",errorClass:"lazyerror",autosizesClass:"lazyautosizes",fastLoadedClass:"ls-is-cached",iframeLoadMode:0,srcAttr:"data-src",srcsetAttr:"data-srcset",sizesAttr:"data-sizes",minSize:40,customMedia:{},init:true,expFactor:1.5,hFac:.8,loadMode:2,loadHidden:true,ricTimeout:0,throttleDelay:125};H=u.lazySizesConfig||u.lazysizesConfig||{};for(e in t){if(!(e in H)){H[e]=t[e]}}}(),!D||!D.getElementsByClassName){return{init:function(){},cfg:H,noSupport:true}}var O=D.documentElement,i=u.HTMLPictureElement,P="addEventListener",$="getAttribute",q=u[P].bind(u),I=u.setTimeout,U=u.requestAnimationFrame||I,o=u.requestIdleCallback,j=/^picture$/i,r=["load","error","lazyincluded","_lazyloaded"],a={},G=Array.prototype.forEach,J=function(e,t){if(!a[t]){a[t]=new RegExp("(\\s|^)"+t+"(\\s|$)")}return a[t].test(e[$]("class")||"")&&a[t]},K=function(e,t){if(!J(e,t)){e.setAttribute("class",(e[$]("class")||"").trim()+" "+t)}},Q=function(e,t){var a;if(a=J(e,t)){e.setAttribute("class",(e[$]("class")||"").replace(a," "))}},V=function(t,a,e){var i=e?P:"removeEventListener";if(e){V(t,a)}r.forEach(function(e){t[i](e,a)})},X=function(e,t,a,i,r){var n=D.createEvent("Event");if(!a){a={}}a.instance=k;n.initEvent(t,!i,!r);n.detail=a;e.dispatchEvent(n);return n},Y=function(e,t){var a;if(!i&&(a=u.picturefill||H.pf)){if(t&&t.src&&!e[$]("srcset")){e.setAttribute("srcset",t.src)}a({reevaluate:true,elements:[e]})}else if(t&&t.src){e.src=t.src}},Z=function(e,t){return(getComputedStyle(e,null)||{})[t]},s=function(e,t,a){a=a||e.offsetWidth;while(a49?function(){o(t,{timeout:n});if(n!==H.ricTimeout){n=H.ricTimeout}}:te(function(){I(t)},true);return function(e){var t;if(e=e===true){n=33}if(a){return}a=true;t=r-(f.now()-i);if(t<0){t=0}if(e||t<9){s()}else{I(s,t)}}},ie=function(e){var t,a;var i=99;var r=function(){t=null;e()};var n=function(){var e=f.now()-a;if(e0;if(r&&Z(i,"overflow")!="visible"){a=i.getBoundingClientRect();r=C>a.left&&pa.top-1&&g500&&O.clientWidth>500?500:370:H.expand;k._defEx=u;f=u*H.expFactor;c=H.hFac;A=null;if(w2&&h>2&&!D.hidden){w=f;N=0}else if(h>1&&N>1&&M<6){w=u}else{w=_}}if(l!==n){y=innerWidth+n*c;z=innerHeight+n;s=n*-1;l=n}a=d[t].getBoundingClientRect();if((b=a.bottom)>=s&&(g=a.top)<=z&&(C=a.right)>=s*c&&(p=a.left)<=y&&(b||C||p||g)&&(H.loadHidden||x(d[t]))&&(m&&M<3&&!o&&(h<3||N<4)||W(d[t],n))){R(d[t]);r=true;if(M>9){break}}else if(!r&&m&&!i&&M<4&&N<4&&h>2&&(v[0]||H.preloadAfterLoad)&&(v[0]||!o&&(b||C||p||g||d[t][$](H.sizesAttr)!="auto"))){i=v[0]||d[t]}}if(i&&!r){R(i)}}};var a=ae(t);var S=function(e){var t=e.target;if(t._lazyCache){delete t._lazyCache;return}L(e);K(t,H.loadedClass);Q(t,H.loadingClass);V(t,B);X(t,"lazyloaded")};var i=te(S);var B=function(e){i({target:e.target})};var T=function(e,t){var a=e.getAttribute("data-load-mode")||H.iframeLoadMode;if(a==0){e.contentWindow.location.replace(t)}else if(a==1){e.src=t}};var F=function(e){var t;var a=e[$](H.srcsetAttr);if(t=H.customMedia[e[$]("data-media")||e[$]("media")]){e.setAttribute("media",t)}if(a){e.setAttribute("srcset",a)}};var s=te(function(t,e,a,i,r){var n,s,o,l,u,f;if(!(u=X(t,"lazybeforeunveil",e)).defaultPrevented){if(i){if(a){K(t,H.autosizesClass)}else{t.setAttribute("sizes",i)}}s=t[$](H.srcsetAttr);n=t[$](H.srcAttr);if(r){o=t.parentNode;l=o&&j.test(o.nodeName||"")}f=e.firesLoad||"src"in t&&(s||n||l);u={target:t};K(t,H.loadingClass);if(f){clearTimeout(c);c=I(L,2500);V(t,B,true)}if(l){G.call(o.getElementsByTagName("source"),F)}if(s){t.setAttribute("srcset",s)}else if(n&&!l){if(d.test(t.nodeName)){T(t,n)}else{t.src=n}}if(r&&(s||l)){Y(t,{src:n})}}if(t._lazyRace){delete t._lazyRace}Q(t,H.lazyClass);ee(function(){var e=t.complete&&t.naturalWidth>1;if(!f||e){if(e){K(t,H.fastLoadedClass)}S(u);t._lazyCache=true;I(function(){if("_lazyCache"in t){delete t._lazyCache}},9)}if(t.loading=="lazy"){M--}},true)});var R=function(e){if(e._lazyRace){return}var t;var a=n.test(e.nodeName);var i=a&&(e[$](H.sizesAttr)||e[$]("sizes"));var r=i=="auto";if((r||!m)&&a&&(e[$]("src")||e.srcset)&&!e.complete&&!J(e,H.errorClass)&&J(e,H.lazyClass)){return}t=X(e,"lazyunveilread").detail;if(r){re.updateElem(e,true,e.offsetWidth)}e._lazyRace=true;M++;s(e,t,r,i,a)};var r=ie(function(){H.loadMode=3;a()});var o=function(){if(H.loadMode==3){H.loadMode=2}r()};var l=function(){if(m){return}if(f.now()-e<999){I(l,999);return}m=true;H.loadMode=3;a();q("scroll",o,true)};return{_:function(){e=f.now();k.elements=D.getElementsByClassName(H.lazyClass);v=D.getElementsByClassName(H.lazyClass+" "+H.preloadClass);q("scroll",a,true);q("resize",a,true);q("pageshow",function(e){if(e.persisted){var t=D.querySelectorAll("."+H.loadingClass);if(t.length&&t.forEach){U(function(){t.forEach(function(e){if(e.complete){R(e)}})})}}});if(u.MutationObserver){new MutationObserver(a).observe(O,{childList:true,subtree:true,attributes:true})}else{O[P]("DOMNodeInserted",a,true);O[P]("DOMAttrModified",a,true);setInterval(a,999)}q("hashchange",a,true);["focus","mouseover","click","load","transitionend","animationend"].forEach(function(e){D[P](e,a,true)});if(/d$|^c/.test(D.readyState)){l()}else{q("load",l);D[P]("DOMContentLoaded",a);I(l,2e4)}if(k.elements.length){t();ee._lsFlush()}else{a()}},checkElems:a,unveil:R,_aLSL:o}}(),re=function(){var a;var n=te(function(e,t,a,i){var r,n,s;e._lazysizesWidth=i;i+="px";e.setAttribute("sizes",i);if(j.test(t.nodeName||"")){r=t.getElementsByTagName("source");for(n=0,s=r.length;n 2 | 3 | 4 | 5 | 6 | 7 | controlling retina/density of responsive images with lazysizes and the optimumx plugin 8 | 9 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 |
43 |
44 |

The srcset with the sizes attribute is definitely the way to go to create responsive, flexibel, adaptive images.

45 |

Unfortunately there is no way to tell the browser, that a specific image doesn't gain much perceived quality with a higher density or that image quality of a specific image isn't important for the user experience.

46 |

Due to the fact, that a 2x retina means 4x data and 3x retina means 9x data, performance can suffer even on good connections badly.

47 |

lazySizes data-optimumx feature (build on top of data-sizes="auto") gives the developer more control to use adaptive images markup, but opt-out from to high retina at some point by defining the optimum density.

48 |
49 |
50 |

Unfortunately this demo makes only sense, if you are using a retina device. Maybe come back with one (tablet / smartphone)? Sorry!

51 |
52 |
53 |
Configure the data-optimumx attribute
54 |
55 |
56 |
57 | data-optimumx 58 |
59 |
60 |
61 | 62 | 63 |
64 |
65 |
66 | 67 |
68 |
69 |
70 |
71 | 72 |
73 |
74 | 75 |
76 |
77 | 78 |
79 |
80 |
81 |
82 |
83 |
84 | 85 | 86 |
87 |
88 |
89 | 92 |
93 |

Wether viewport should be changed while dragging (input/checked) or on drag release (change/unchecked).

94 |
95 |
96 |
97 |
98 |
99 |
100 | 101 | 102 |
103 | 104 | 105 | 106 | -------------------------------------------------------------------------------- /optimumx/js/parent.js: -------------------------------------------------------------------------------- 1 | (function(window, document){ 2 | 3 | if ( window.HTMLPictureElement ) { 4 | $('html').addClass('resp-supported'); 5 | } 6 | 7 | if ( (window.devicePixelRatio || 1) < 1.4 ) { 8 | $('html').addClass('no-retina'); 9 | } 10 | 11 | webshim.setOptions('forms-ext', { 12 | replaceUI: 'auto' 13 | }); 14 | 15 | 16 | webshim.polyfill('forms forms-ext'); 17 | 18 | 19 | $(function(){ 20 | var oninput; 21 | 22 | $('#vw-input') 23 | .on('change.smooth-vwchange', function(){ 24 | oninput = $.prop(this, 'checked'); 25 | }) 26 | .trigger('change.smooth-vwchange') 27 | ; 28 | $('#viewport').each(function(){ 29 | var onChange = function(e){ 30 | if (!e || (oninput && e.type == 'input') || (e.type == 'change' && !oninput)){ 31 | var val = $(this).val(); 32 | $('#arena').width(val+'%'); 33 | } 34 | }; 35 | $(this).on('input change', onChange).each(onChange); 36 | }); 37 | $('#arena').removeAttr('src').prop('src', 'javascript:false'); 38 | 39 | 40 | 41 | $('.arena-config') 42 | .on('submit', function(){ 43 | var data = $(this).serialize(); 44 | $('#arena').prop('src', 'child.html?' + data); 45 | return false; 46 | }) 47 | ; 48 | 49 | $('.btn-optimum').on('click', function(){ 50 | $('#arena').prop('src', 'child.html?'+ (new Date().getTime())); 51 | return false; 52 | }); 53 | $('.btn-auto').on('click', function(){ 54 | $('#arena').prop('src', 'child.html?optimumx=auto'); 55 | return false; 56 | }); 57 | $('#arena').prop('src', 'child.html'); 58 | }) 59 | 60 | })(window, document); 61 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "lazysizes", 3 | "version": "5.3.2", 4 | "filename": "lazysizes.min.js", 5 | "license": "MIT", 6 | "author": "Alexander Farkas ", 7 | "scripts": { 8 | "build": "grunt && tsc && grunt importTs", 9 | "prepublishOnly": "npm run build" 10 | }, 11 | "repository": { 12 | "type": "git", 13 | "url": "git://github.com/aFarkas/lazysizes.git" 14 | }, 15 | "namespace": "lazySizes", 16 | "main": "lazysizes.js", 17 | "browser": "lazysizes.js", 18 | "types": "lazysizes.d.ts", 19 | "devDependencies": { 20 | "grunt": "~1.1.0", 21 | "grunt-bytesize": "~0.2.0", 22 | "grunt-cli": "~1.3", 23 | "grunt-contrib-jshint": "^2.1.0", 24 | "grunt-contrib-qunit": "^3.1.0", 25 | "grunt-contrib-uglify": "^4.0.1", 26 | "grunt-contrib-watch": "~1.1.0", 27 | "grunt-max-filesize": "^0.1.1", 28 | "grunt-uncss": "~0.9.1", 29 | "jquery": "^3.5.1", 30 | "jquery-deparam": "^0.5.3", 31 | "picturefill": "^3.0.3", 32 | "qunitjs": "^2.4.1", 33 | "respimage": "^1.4.2", 34 | "typescript": "^4.1.5" 35 | }, 36 | "npmName": "lazysizes", 37 | "npmFileMap": [ 38 | { 39 | "basePath": "", 40 | "files": [ 41 | "lazysizes.min.js", 42 | "plugins/**/*.min.js" 43 | ] 44 | } 45 | ], 46 | "description": "High performance (jankfree) lazy loader for images (including responsive images), iframes and scripts (widgets).", 47 | "keywords": [ 48 | "lazy", 49 | "loader", 50 | "lazyloader", 51 | "lazyload", 52 | "lazySizes", 53 | "performance", 54 | "responsive", 55 | "image", 56 | "images", 57 | "responsive images", 58 | "picture", 59 | "srcset", 60 | "respimg", 61 | "respimage", 62 | "include", 63 | "ajax", 64 | "img", 65 | "imager", 66 | "imager.js", 67 | "picturefill", 68 | "component" 69 | ] 70 | } 71 | -------------------------------------------------------------------------------- /plugins/README.md: -------------------------------------------------------------------------------- 1 | # lazysizes plugins/extensions/snippets 2 | 3 | **lazysizes** works out of the box with standard and responsive images (``src``, ``srcset`` and ``picture``) and iframes. 4 | 5 | The scripts in this folder can be used as extensions or as boilerplate snippets to extend and adjust lazysizes to your needs. 6 | -------------------------------------------------------------------------------- /plugins/artdirect/README.md: -------------------------------------------------------------------------------- 1 | # lazysizes artdirect extension 2 | 3 | The artdirect extension allows you to fully control art direction through your CSS. This is accomplished by two techniques which you can be used separately or combined. The extension hooks into the `data-sizes="auto"` feature. 4 | 5 | The first feature is by tagging and the second feature uses the information of the displayed aspect ratio of the `img` elements and the physical aspect ratio of your images. 6 | 7 | ## Enabling artdirect extension for a ``picture > img`` 8 | 9 | You can either enable the artdirect extension for all images using JavaScript: 10 | 11 | ```js 12 | // never try to import *.min.js files 13 | import lazySizes from 'lazysizes'; 14 | import 'lazysizes/plugins/artdiect/ls.artdirect'; 15 | 16 | lazySizes.cfg.autoArtDirect = true; 17 | ``` 18 | 19 | Or for a specific `img` element using CSS: 20 | 21 | ```css 22 | picture > img.is-autoartdirect { 23 | font-family: "artdirect"; 24 | } 25 | ``` 26 | 27 | ## Tagging `source` elements and controlling it via CSS 28 | 29 | You can use a whitespace separated list of tags on the `source` elements `data-tag` attribute as also a whitespace separated list of tags inside of the CSS `font-family`: 30 | 31 | ```html 32 | 43 | 44 | 45 | 48 | 51 | image with artdirection 57 | 58 | ``` 59 | 60 | ## Providing aspect ratio information of physical images 61 | 62 | By providing the specific layout height and width (no `auto` values) through CSS and providing the physical aspect ratio of the images through either a `data-aspectratio` attribute or through `w` **and**`h` descriptors or through `width` and `height` content attributes the plugin can choose the best image source. 63 | 64 | ```html 65 | 77 | 78 | 79 | 83 | 87 | image with artdirection 93 | 94 | ``` 95 | 96 | The aspect ratio feature can be perfectly combined with the tagging feature. 97 | 98 | ```html 99 | 113 | 114 | 115 | 120 | 124 | 129 | image with artdirection 135 | 136 | ``` 137 | 138 | 139 | -------------------------------------------------------------------------------- /plugins/artdirect/ls.artdirect.js: -------------------------------------------------------------------------------- 1 | (function(window, factory) { 2 | if (!window) {return;} 3 | var globalInstall = function(){ 4 | factory(window.lazySizes); 5 | window.removeEventListener('lazyunveilread', globalInstall, true); 6 | }; 7 | 8 | factory = factory.bind(null, window, window.document); 9 | 10 | if(typeof module == 'object' && module.exports){ 11 | factory(require('lazysizes')); 12 | } else if (typeof define == 'function' && define.amd) { 13 | define(['lazysizes'], factory); 14 | } else if(window.lazySizes) { 15 | globalInstall(); 16 | } else { 17 | window.addEventListener('lazyunveilread', globalInstall, true); 18 | } 19 | }(typeof window != 'undefined' ? 20 | window : 0, function(window, document, lazySizes) { 21 | 'use strict'; 22 | 23 | if(!window.addEventListener){return;} 24 | var lazySizesConfig = lazySizes.cfg; 25 | 26 | var ElementPrototype = (window.Element || Node || window.HTMLElement).prototype; 27 | var regArtDirect = /artdirect/; 28 | var regDescriptors = /\s+(\d+)(w|h)\s+(\d+)(w|h)/; 29 | var regArtDirectTags = /artdirect["']*\s*:\s*["']*(.+?)(?=($|'|"|;))/; 30 | var regPicture = /^picture$/i; 31 | var regSplit = /[\s,]+/g; 32 | var slice = [].slice; 33 | 34 | function getCandidatesAspectRatio(element){ 35 | var match, width, height; 36 | var ratio = parseFloat(element.getAttribute('data-aspectratio')); 37 | var srcset = element.getAttribute(lazySizesConfig.srcsetAttr) || element.getAttribute('srcset'); 38 | 39 | 40 | if(!ratio){ 41 | match = srcset.match(regDescriptors); 42 | 43 | if (match) { 44 | if(match[2] == 'w'){ 45 | width = match[1]; 46 | height = match[3]; 47 | } else { 48 | width = match[3]; 49 | height = match[1]; 50 | } 51 | } else { 52 | width = element.getAttribute('width'); 53 | height = element.getAttribute('height'); 54 | } 55 | 56 | ratio = width / height; 57 | } 58 | 59 | return ratio; 60 | } 61 | 62 | function getLayoutAspectRatio(element){ 63 | return element.offsetWidth / element.offsetHeight; 64 | } 65 | 66 | function toTagSelector(tag){ 67 | return 'source[data-tag~="' + tag + '"]'; 68 | } 69 | 70 | function getArtDirectConfig(img){ 71 | var picture = img.parentNode; 72 | var isPicture = regPicture.test(picture.nodeName || ''); 73 | var content = (window.getComputedStyle(img) || {}).fontFamily; 74 | var config = null; 75 | 76 | if(isPicture && (lazySizesConfig.autoArtDirect || regArtDirect.test(content || ''))){ 77 | config = { 78 | picture: picture, 79 | img: img, 80 | tags: content.match(regArtDirectTags) 81 | }; 82 | 83 | if(config.tags){ 84 | config.selector = config.tags[1].split(regSplit).map(toTagSelector).join(','); 85 | } 86 | } 87 | 88 | return config; 89 | } 90 | 91 | function toSourceObj(source){ 92 | var media = source.getAttribute('media'); 93 | 94 | return { 95 | source: source, 96 | aspectRatio: getCandidatesAspectRatio(source), 97 | isSelected: !media || window.matchMedia(media).matches, 98 | }; 99 | } 100 | 101 | function sortAspectRatio(source1, source2){ 102 | return source1.aspectRatio < source2.aspectRatio; 103 | } 104 | 105 | function getClosestSource(sources, aspecRatio){ 106 | var i, len; 107 | var closest = sources[0]; 108 | 109 | for(i = 1, len = sources.length; i < len; i++){ 110 | if(Math.abs(closest.aspectRatio - aspecRatio) > Math.abs(sources[i].aspectRatio - aspecRatio)){ 111 | closest = sources[i]; 112 | } 113 | } 114 | 115 | return closest; 116 | } 117 | 118 | function setMedia(source, media){ 119 | source._lsMedia = media; 120 | lazySizes.rAF(function(){ 121 | if(source._lsMedia){ 122 | delete source._lsMedia; 123 | } 124 | source.setAttribute('media', media); 125 | }); 126 | } 127 | 128 | function selectSource(imgCfg){ 129 | var imgAspectRatio = getLayoutAspectRatio(imgCfg.img); 130 | var sources = slice.call(imgCfg.picture.getElementsByTagName('source')) 131 | .map(toSourceObj) 132 | .sort(sortAspectRatio) 133 | ; 134 | var matchedSources = imgCfg.selector ? 135 | sources.filter(function(source){ 136 | return source.source.matches(imgCfg.selector); 137 | }) : 138 | sources 139 | ; 140 | var closestSource = getClosestSource(matchedSources, imgAspectRatio); 141 | 142 | if(!closestSource.isSelected){ 143 | setMedia(closestSource.source, '(min-width: 1px)'); 144 | } 145 | 146 | sources 147 | .filter(function(source){ 148 | return (source != closestSource && source.isSelected); 149 | }) 150 | .forEach(function (source) { 151 | setMedia(source.source, '(x)'); 152 | }) 153 | ; 154 | } 155 | 156 | function addAutoArtDirection(e){ 157 | 158 | if(e.detail.instance != lazySizes){return;} 159 | 160 | var img = e.target; 161 | var imgCfg = getArtDirectConfig(img); 162 | 163 | if(imgCfg){ 164 | selectSource(imgCfg); 165 | } 166 | } 167 | 168 | if(!ElementPrototype.matches){ 169 | ElementPrototype.matches = ElementPrototype.matchesSelector || 170 | ElementPrototype.webkitMatchesSelector || 171 | ElementPrototype.msMatchesSelector || 172 | ElementPrototype.oMatchesSelector; 173 | } 174 | 175 | window.addEventListener('lazybeforesizes', addAutoArtDirection, true); 176 | })); 177 | -------------------------------------------------------------------------------- /plugins/artdirect/ls.artdirect.min.js: -------------------------------------------------------------------------------- 1 | /*! lazysizes - v5.3.2 */ 2 | 3 | !function(e,t){var i;e&&(i=function(){t(e.lazySizes),e.removeEventListener("lazyunveilread",i,!0)},t=t.bind(null,e,e.document),"object"==typeof module&&module.exports?t(require("lazysizes")):"function"==typeof define&&define.amd?define(["lazysizes"],t):e.lazySizes?i():e.addEventListener("lazyunveilread",i,!0))}("undefined"!=typeof window?window:0,function(o,e,u){"use strict";var d,t,l,f,m,h,p,s;function g(e){return'source[data-tag~="'+e+'"]'}function n(e){var t,i,a,r,s,n,c=e.getAttribute("media");return{source:e,aspectRatio:(t=e,s=parseFloat(t.getAttribute("data-aspectratio")),n=t.getAttribute(d.srcsetAttr)||t.getAttribute("srcset"),s||(r=(i=n.match(f))?"w"==i[2]?(a=i[1],i[3]):(a=i[3],i[1]):(a=t.getAttribute("width"),t.getAttribute("height")),s=a/r),s),isSelected:!c||o.matchMedia(c).matches}}function c(e,t){return e.aspectRatioMath.abs(e[a].aspectRatio-t)&&(i=e[a]);return i}(t.selector?a.filter(function(e){return e.source.matches(t.selector)}):a,i);r.isSelected||y(r.source,"(min-width: 1px)"),a.filter(function(e){return e!=r&&e.isSelected}).forEach(function(e){y(e.source,"(x)")})}o.addEventListener&&(d=u.cfg,t=(o.Element||Node||o.HTMLElement).prototype,l=/artdirect/,f=/\s+(\d+)(w|h)\s+(\d+)(w|h)/,m=/artdirect["']*\s*:\s*["']*(.+?)(?=($|'|"|;))/,h=/^picture$/i,p=/[\s,]+/g,s=[].slice,t.matches||(t.matches=t.matchesSelector||t.webkitMatchesSelector||t.msMatchesSelector||t.oMatchesSelector),o.addEventListener("lazybeforesizes",function(e){var t,i,a,r,s,n,c;e.detail.instance==u&&(t=e.target,r=(a=t).parentNode,s=h.test(r.nodeName||""),n=(o.getComputedStyle(a)||{}).fontFamily,c=null,s&&(d.autoArtDirect||l.test(n||""))&&(c={picture:r,img:a,tags:n.match(m)}).tags&&(c.selector=c.tags[1].split(p).map(g).join(",")),(i=c)&&b(i))},!0))}); -------------------------------------------------------------------------------- /plugins/aspectratio/README.md: -------------------------------------------------------------------------------- 1 | # lazysizes aspectratio extension 2 | 3 | This plugin helps to pre-occupy the space needed for an image by calculating the height from the image width or the width from the height (This means the width or height has to be calculable before the image is loaded). This can serve as an alternative to the different CSS intrinsic ratio patterns. 4 | 5 | Note: The CSS patterns are recommended, but especially in case of different ratio's for art directed images not so convenient. This plugin removes the ``data-aspectratio`` attribute after processing each image and my not play well with other plugins that rely on this attribute. 6 | 7 | ## Markup API: 8 | 9 | The value of the ``data-aspectratio`` has to be defined as the *width* divided by the *height* of the image and can be represented as a ratio or a floating point number. 10 | 11 | Example values for an image with a width of 400 and a height of 200 (all mean the same): ``"400/200"``, ``"4/2"``, ``"2/1"``, ``"2"``, ``"2.0"`` 12 | 13 | ```html 14 | 21 | 22 | 23 | 24 | 28 | 32 | 36 | 39 | 40 | 41 | image with artdirection 47 | 48 | ``` 49 | 50 | ## JS API 51 | 52 | In case new elements are added to the DOM the global ``imageRatio.processImages`` method can be used. The method takes either an element representing the container/wrapper of the new elements or a list of image elements: 53 | 54 | ```js 55 | imageRatio.processImages(document.querySelector('#dynaimc-wrapper'); 56 | imageRatio.processImages(document.querySelectorAll('#dynaimc-wrapper img[data-aspectratio]'); 57 | ``` 58 | 59 | In case jQuery, ZEPTO, shoestring or another jQuery-like library is used the ``imageRatio`` plugin is added also: 60 | 61 | ```js 62 | $('.dynamic-wrapper').imageRatio(); 63 | $('.dynamic-wrapper img[data-aspectratio]').imageRatio(); 64 | ``` 65 | 66 | Note: This plugin can also be used without lazySizes core script. 67 | -------------------------------------------------------------------------------- /plugins/aspectratio/ls.aspectratio.js: -------------------------------------------------------------------------------- 1 | (function(window, factory) { 2 | var globalInstall = function(){ 3 | factory(window.lazySizes); 4 | window.removeEventListener('lazyunveilread', globalInstall, true); 5 | }; 6 | 7 | factory = factory.bind(null, window, window.document); 8 | 9 | if(typeof module == 'object' && module.exports){ 10 | factory(require('lazysizes')); 11 | } else if (typeof define == 'function' && define.amd) { 12 | define(['lazysizes'], factory); 13 | } else if(window.lazySizes) { 14 | globalInstall(); 15 | } else { 16 | window.addEventListener('lazyunveilread', globalInstall, true); 17 | } 18 | }(window, function(window, document, lazySizes) { 19 | 'use strict'; 20 | 21 | if(!window.addEventListener){return;} 22 | 23 | var forEach = Array.prototype.forEach; 24 | 25 | var imageRatio, extend$, $; 26 | 27 | var regPicture = /^picture$/i; 28 | var aspectRatioAttr = 'data-aspectratio'; 29 | var aspectRatioSel = 'img[' + aspectRatioAttr + ']'; 30 | 31 | var matchesMedia = function(media){ 32 | if(window.matchMedia){ 33 | matchesMedia = function(media){ 34 | return !media || (matchMedia(media) || {}).matches; 35 | }; 36 | } else if(window.Modernizr && Modernizr.mq){ 37 | return !media || Modernizr.mq(media); 38 | } else { 39 | return !media; 40 | } 41 | return matchesMedia(media); 42 | }; 43 | 44 | var addClass = lazySizes.aC; 45 | var removeClass = lazySizes.rC; 46 | var lazySizesConfig = lazySizes.cfg; 47 | 48 | function AspectRatio(){ 49 | this.ratioElems = document.getElementsByClassName('lazyaspectratio'); 50 | this._setupEvents(); 51 | this.processImages(); 52 | } 53 | 54 | AspectRatio.prototype = { 55 | _setupEvents: function(){ 56 | var module = this; 57 | 58 | var addRemoveAspectRatio = function(elem){ 59 | if(elem.naturalWidth < 36){ 60 | module.addAspectRatio(elem, true); 61 | } else { 62 | module.removeAspectRatio(elem, true); 63 | } 64 | }; 65 | var onload = function(){ 66 | module.processImages(); 67 | }; 68 | 69 | document.addEventListener('load', function(e){ 70 | if(e.target.getAttribute && e.target.getAttribute(aspectRatioAttr)){ 71 | addRemoveAspectRatio(e.target); 72 | } 73 | }, true); 74 | 75 | addEventListener('resize', (function(){ 76 | var timer; 77 | var resize = function(){ 78 | forEach.call(module.ratioElems, addRemoveAspectRatio); 79 | }; 80 | 81 | return function(){ 82 | clearTimeout(timer); 83 | timer = setTimeout(resize, 99); 84 | }; 85 | })()); 86 | 87 | document.addEventListener('DOMContentLoaded', onload); 88 | 89 | addEventListener('load', onload); 90 | }, 91 | processImages: function(context){ 92 | var elements, i; 93 | 94 | if(!context){ 95 | context = document; 96 | } 97 | 98 | if('length' in context && !context.nodeName){ 99 | elements = context; 100 | } else { 101 | elements = context.querySelectorAll(aspectRatioSel); 102 | } 103 | 104 | for(i = 0; i < elements.length; i++){ 105 | if(elements[i].naturalWidth > 36){ 106 | this.removeAspectRatio(elements[i]); 107 | continue; 108 | } 109 | this.addAspectRatio(elements[i]); 110 | } 111 | }, 112 | getSelectedRatio: function(img){ 113 | var i, len, sources, customMedia, ratio; 114 | var parent = img.parentNode; 115 | if(parent && regPicture.test(parent.nodeName || '')){ 116 | sources = parent.getElementsByTagName('source'); 117 | 118 | for(i = 0, len = sources.length; i < len; i++){ 119 | customMedia = sources[i].getAttribute('data-media') || sources[i].getAttribute('media'); 120 | 121 | if(lazySizesConfig.customMedia[customMedia]){ 122 | customMedia = lazySizesConfig.customMedia[customMedia]; 123 | } 124 | 125 | if(matchesMedia(customMedia)){ 126 | ratio = sources[i].getAttribute(aspectRatioAttr); 127 | break; 128 | } 129 | } 130 | } 131 | 132 | return ratio || img.getAttribute(aspectRatioAttr) || ''; 133 | }, 134 | parseRatio: (function(){ 135 | var regRatio = /^\s*([+\d\.]+)(\s*[\/x]\s*([+\d\.]+))?\s*$/; 136 | var ratioCache = {}; 137 | return function(ratio){ 138 | var match; 139 | 140 | if(!ratioCache[ratio] && (match = ratio.match(regRatio))){ 141 | if(match[3]){ 142 | ratioCache[ratio] = match[1] / match[3]; 143 | } else { 144 | ratioCache[ratio] = match[1] * 1; 145 | } 146 | } 147 | 148 | return ratioCache[ratio]; 149 | }; 150 | })(), 151 | addAspectRatio: function(img, notNew){ 152 | var ratio; 153 | var width = img.offsetWidth; 154 | var height = img.offsetHeight; 155 | 156 | if(!notNew){ 157 | addClass(img, 'lazyaspectratio'); 158 | } 159 | 160 | if(width < 36 && height <= 0){ 161 | if(width || height && window.console){ 162 | console.log('Define width or height of image, so we can calculate the other dimension'); 163 | } 164 | return; 165 | } 166 | 167 | ratio = this.getSelectedRatio(img); 168 | ratio = this.parseRatio(ratio); 169 | 170 | if(ratio){ 171 | if(width){ 172 | img.style.height = (width / ratio) + 'px'; 173 | } else { 174 | img.style.width = (height * ratio) + 'px'; 175 | } 176 | } 177 | }, 178 | removeAspectRatio: function(img){ 179 | removeClass(img, 'lazyaspectratio'); 180 | img.style.height = ''; 181 | img.style.width = ''; 182 | img.removeAttribute(aspectRatioAttr); 183 | } 184 | }; 185 | 186 | extend$ = function(){ 187 | $ = window.jQuery || window.Zepto || window.shoestring || window.$; 188 | if($ && $.fn && !$.fn.imageRatio && $.fn.filter && $.fn.add && $.fn.find){ 189 | $.fn.imageRatio = function(){ 190 | imageRatio.processImages(this.find(aspectRatioSel).add(this.filter(aspectRatioSel))); 191 | return this; 192 | }; 193 | } else { 194 | $ = false; 195 | } 196 | }; 197 | 198 | extend$(); 199 | setTimeout(extend$); 200 | 201 | imageRatio = new AspectRatio(); 202 | 203 | window.imageRatio = imageRatio; 204 | 205 | if(typeof module == 'object' && module.exports){ 206 | module.exports = imageRatio; 207 | } else if (typeof define == 'function' && define.amd) { 208 | define(imageRatio); 209 | } 210 | 211 | })); 212 | -------------------------------------------------------------------------------- /plugins/aspectratio/ls.aspectratio.min.js: -------------------------------------------------------------------------------- 1 | /*! lazysizes - v5.3.2 */ 2 | 3 | !function(e,t){var i=function(){t(e.lazySizes),e.removeEventListener("lazyunveilread",i,!0)};t=t.bind(null,e,e.document),"object"==typeof module&&module.exports?t(require("lazysizes")):"function"==typeof define&&define.amd?define(["lazysizes"],t):e.lazySizes?i():e.addEventListener("lazyunveilread",i,!0)}(window,function(o,r,e){"use strict";var s,t,i,n,d,c,a,u,f,l,m,h,p;function g(){this.ratioElems=r.getElementsByClassName("lazyaspectratio"),this._setupEvents(),this.processImages()}o.addEventListener&&(s=Array.prototype.forEach,d=/^picture$/i,a="img["+(c="data-aspectratio")+"]",u=function(e){return o.matchMedia?(u=function(e){return!e||(matchMedia(e)||{}).matches})(e):o.Modernizr&&Modernizr.mq?!e||Modernizr.mq(e):!e},f=e.aC,l=e.rC,m=e.cfg,g.prototype={_setupEvents:function(){function t(e){e.naturalWidth<36?n.addAspectRatio(e,!0):n.removeAspectRatio(e,!0)}function e(){n.processImages()}var i,n=this;function a(){s.call(n.ratioElems,t)}r.addEventListener("load",function(e){e.target.getAttribute&&e.target.getAttribute(c)&&t(e.target)},!0),addEventListener("resize",function(){clearTimeout(i),i=setTimeout(a,99)}),r.addEventListener("DOMContentLoaded",e),addEventListener("load",e)},processImages:function(e){for(var t=("length"in(e=e||r)&&!e.nodeName?e:e.querySelectorAll(a)),i=0;i 11 | function loadJS(u){var r=document.getElementsByTagName("script")[0],s=document.createElement("script");s.src=u;r.parentNode.insertBefore(s,r);} 12 | 13 | if(!window.HTMLPictureElement || !('sizes' in document.createElement('img'))){ 14 | loadJS("ls.respimg.min.js"); 15 | } 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 |
26 | ``` 27 | 28 | The bgset also supports art direction through multiple media query sets. To use this feature each set has to be separated using the ``" | "`` signs and the media query has to be added at the end of the set inside of square brackets. 29 | 30 | Also the ``customMedia`` option can be used to separate the media queries implementation from the markup. 31 | 32 | ```html 33 | 40 | 41 |
42 | 43 |
44 | 45 |
46 | ``` 47 | 48 | Of course also resolution switching and art direction can be combined: 49 | 50 | ```html 51 |
54 | ``` 55 | 56 | Here you find a [small bgset demo](http://jsfiddle.net/trixta/bfqqnosp/embedded/result/). 57 | 58 | **Note: In case you use this plugin with ``background-size: cover|contain`` and the ``data-sizes="auto"`` feature, we recommend to also use the [parent-fit extension](../parent-fit/) to calculate the right ``sizes`` attribute for you. See also the following [demo](http://jsfiddle.net/trixta/w96o9xm5/). In these cases the [object-fit polyfill plugin](../object-fit) should be a better option than bgset.** 59 | -------------------------------------------------------------------------------- /plugins/bgset/ls.bgset.js: -------------------------------------------------------------------------------- 1 | (function(window, factory) { 2 | var globalInstall = function(){ 3 | factory(window.lazySizes); 4 | window.removeEventListener('lazyunveilread', globalInstall, true); 5 | }; 6 | 7 | factory = factory.bind(null, window, window.document); 8 | 9 | if(typeof module == 'object' && module.exports){ 10 | factory(require('lazysizes')); 11 | } else if (typeof define == 'function' && define.amd) { 12 | define(['lazysizes'], factory); 13 | } else if(window.lazySizes) { 14 | globalInstall(); 15 | } else { 16 | window.addEventListener('lazyunveilread', globalInstall, true); 17 | } 18 | }(window, function(window, document, lazySizes) { 19 | 'use strict'; 20 | if(!window.addEventListener){return;} 21 | 22 | var lazySizesCfg = lazySizes.cfg; 23 | var regWhite = /\s+/g; 24 | var regSplitSet = /\s*\|\s+|\s+\|\s*/g; 25 | var regSource = /^(.+?)(?:\s+\[\s*(.+?)\s*\])(?:\s+\[\s*(.+?)\s*\])?$/; 26 | var regType = /^\s*\(*\s*type\s*:\s*(.+?)\s*\)*\s*$/; 27 | var regBgUrlEscape = /\(|\)|'/; 28 | var allowedBackgroundSize = {contain: 1, cover: 1}; 29 | var proxyWidth = function(elem){ 30 | var width = lazySizes.gW(elem, elem.parentNode); 31 | 32 | if(!elem._lazysizesWidth || width > elem._lazysizesWidth){ 33 | elem._lazysizesWidth = width; 34 | } 35 | return elem._lazysizesWidth; 36 | }; 37 | var getBgSize = function(elem){ 38 | var bgSize; 39 | 40 | bgSize = (getComputedStyle(elem) || {getPropertyValue: function(){}}).getPropertyValue('background-size'); 41 | 42 | if(!allowedBackgroundSize[bgSize] && allowedBackgroundSize[elem.style.backgroundSize]){ 43 | bgSize = elem.style.backgroundSize; 44 | } 45 | 46 | return bgSize; 47 | }; 48 | var setTypeOrMedia = function(source, match){ 49 | if(match){ 50 | var typeMatch = match.match(regType); 51 | if(typeMatch && typeMatch[1]){ 52 | source.setAttribute('type', typeMatch[1]); 53 | } else { 54 | source.setAttribute('media', lazySizesCfg.customMedia[match] || match); 55 | } 56 | } 57 | }; 58 | var createPicture = function(sets, elem, img){ 59 | var picture = document.createElement('picture'); 60 | var sizes = elem.getAttribute(lazySizesCfg.sizesAttr); 61 | var ratio = elem.getAttribute('data-ratio'); 62 | var optimumx = elem.getAttribute('data-optimumx'); 63 | 64 | if(elem._lazybgset && elem._lazybgset.parentNode == elem){ 65 | elem.removeChild(elem._lazybgset); 66 | } 67 | 68 | Object.defineProperty(img, '_lazybgset', { 69 | value: elem, 70 | writable: true 71 | }); 72 | Object.defineProperty(elem, '_lazybgset', { 73 | value: picture, 74 | writable: true 75 | }); 76 | 77 | sets = sets.replace(regWhite, ' ').split(regSplitSet); 78 | 79 | picture.style.display = 'none'; 80 | img.className = lazySizesCfg.lazyClass; 81 | 82 | if(sets.length == 1 && !sizes){ 83 | sizes = 'auto'; 84 | } 85 | 86 | sets.forEach(function(set){ 87 | var match; 88 | var source = document.createElement('source'); 89 | 90 | if(sizes && sizes != 'auto'){ 91 | source.setAttribute('sizes', sizes); 92 | } 93 | 94 | if((match = set.match(regSource))){ 95 | source.setAttribute(lazySizesCfg.srcsetAttr, match[1]); 96 | 97 | setTypeOrMedia(source, match[2]); 98 | setTypeOrMedia(source, match[3]); 99 | } else { 100 | source.setAttribute(lazySizesCfg.srcsetAttr, set); 101 | } 102 | 103 | picture.appendChild(source); 104 | }); 105 | 106 | if(sizes){ 107 | img.setAttribute(lazySizesCfg.sizesAttr, sizes); 108 | elem.removeAttribute(lazySizesCfg.sizesAttr); 109 | elem.removeAttribute('sizes'); 110 | } 111 | if(optimumx){ 112 | img.setAttribute('data-optimumx', optimumx); 113 | } 114 | if(ratio) { 115 | img.setAttribute('data-ratio', ratio); 116 | } 117 | 118 | picture.appendChild(img); 119 | 120 | elem.appendChild(picture); 121 | }; 122 | 123 | var proxyLoad = function(e){ 124 | if(!e.target._lazybgset){return;} 125 | 126 | var image = e.target; 127 | var elem = image._lazybgset; 128 | var bg = image.currentSrc || image.src; 129 | 130 | 131 | if(bg){ 132 | var useSrc = regBgUrlEscape.test(bg) ? JSON.stringify(bg) : bg; 133 | var event = lazySizes.fire(elem, 'bgsetproxy', { 134 | src: bg, 135 | useSrc: useSrc, 136 | fullSrc: null, 137 | }); 138 | 139 | if(!event.defaultPrevented){ 140 | elem.style.backgroundImage = event.detail.fullSrc || 'url(' + event.detail.useSrc + ')'; 141 | } 142 | } 143 | 144 | if(image._lazybgsetLoading){ 145 | lazySizes.fire(elem, '_lazyloaded', {}, false, true); 146 | delete image._lazybgsetLoading; 147 | } 148 | }; 149 | 150 | addEventListener('lazybeforeunveil', function(e){ 151 | var set, image, elem; 152 | 153 | if(e.defaultPrevented || !(set = e.target.getAttribute('data-bgset'))){return;} 154 | 155 | elem = e.target; 156 | image = document.createElement('img'); 157 | 158 | image.alt = ''; 159 | 160 | image._lazybgsetLoading = true; 161 | e.detail.firesLoad = true; 162 | 163 | createPicture(set, elem, image); 164 | 165 | setTimeout(function(){ 166 | lazySizes.loader.unveil(image); 167 | 168 | lazySizes.rAF(function(){ 169 | lazySizes.fire(image, '_lazyloaded', {}, true, true); 170 | if(image.complete) { 171 | proxyLoad({target: image}); 172 | } 173 | }); 174 | }); 175 | 176 | }); 177 | 178 | document.addEventListener('load', proxyLoad, true); 179 | 180 | window.addEventListener('lazybeforesizes', function(e){ 181 | if(e.detail.instance != lazySizes){return;} 182 | if(e.target._lazybgset && e.detail.dataAttr){ 183 | var elem = e.target._lazybgset; 184 | var bgSize = getBgSize(elem); 185 | 186 | if(allowedBackgroundSize[bgSize]){ 187 | e.target._lazysizesParentFit = bgSize; 188 | 189 | lazySizes.rAF(function(){ 190 | e.target.setAttribute('data-parent-fit', bgSize); 191 | if(e.target._lazysizesParentFit){ 192 | delete e.target._lazysizesParentFit; 193 | } 194 | }); 195 | } 196 | } 197 | }, true); 198 | 199 | document.documentElement.addEventListener('lazybeforesizes', function(e){ 200 | if(e.defaultPrevented || !e.target._lazybgset || e.detail.instance != lazySizes){return;} 201 | e.detail.width = proxyWidth(e.target._lazybgset); 202 | }); 203 | })); 204 | -------------------------------------------------------------------------------- /plugins/bgset/ls.bgset.min.js: -------------------------------------------------------------------------------- 1 | /*! lazysizes - v5.3.2 */ 2 | 3 | !function(e,t){var a=function(){t(e.lazySizes),e.removeEventListener("lazyunveilread",a,!0)};t=t.bind(null,e,e.document),"object"==typeof module&&module.exports?t(require("lazysizes")):"function"==typeof define&&define.amd?define(["lazysizes"],t):e.lazySizes?a():e.addEventListener("lazyunveilread",a,!0)}(window,function(e,z,c){"use strict";var g,y,b,f,r,l,s,v,m;e.addEventListener&&(g=c.cfg,y=/\s+/g,b=/\s*\|\s+|\s+\|\s*/g,f=/^(.+?)(?:\s+\[\s*(.+?)\s*\])(?:\s+\[\s*(.+?)\s*\])?$/,r=/^\s*\(*\s*type\s*:\s*(.+?)\s*\)*\s*$/,l=/\(|\)|'/,s={contain:1,cover:1},v=function(e,t){var a;t&&((a=t.match(r))&&a[1]?e.setAttribute("type",a[1]):e.setAttribute("media",g.customMedia[t]||t))},m=function(e){var t,a,r,i,s;e.target._lazybgset&&(a=(t=e.target)._lazybgset,(r=t.currentSrc||t.src)&&(i=l.test(r)?JSON.stringify(r):r,(s=c.fire(a,"bgsetproxy",{src:r,useSrc:i,fullSrc:null})).defaultPrevented||(a.style.backgroundImage=s.detail.fullSrc||"url("+s.detail.useSrc+")")),t._lazybgsetLoading&&(c.fire(a,"_lazyloaded",{},!1,!0),delete t._lazybgsetLoading))},addEventListener("lazybeforeunveil",function(e){var t,a,r,i,s,l,n,d,u,o;!e.defaultPrevented&&(t=e.target.getAttribute("data-bgset"))&&(u=e.target,(o=z.createElement("img")).alt="",o._lazybgsetLoading=!0,e.detail.firesLoad=!0,a=t,r=u,i=o,s=z.createElement("picture"),l=r.getAttribute(g.sizesAttr),n=r.getAttribute("data-ratio"),d=r.getAttribute("data-optimumx"),r._lazybgset&&r._lazybgset.parentNode==r&&r.removeChild(r._lazybgset),Object.defineProperty(i,"_lazybgset",{value:r,writable:!0}),Object.defineProperty(r,"_lazybgset",{value:s,writable:!0}),a=a.replace(y," ").split(b),s.style.display="none",i.className=g.lazyClass,1!=a.length||l||(l="auto"),a.forEach(function(e){var t,a=z.createElement("source");l&&"auto"!=l&&a.setAttribute("sizes",l),(t=e.match(f))?(a.setAttribute(g.srcsetAttr,t[1]),v(a,t[2]),v(a,t[3])):a.setAttribute(g.srcsetAttr,e),s.appendChild(a)}),l&&(i.setAttribute(g.sizesAttr,l),r.removeAttribute(g.sizesAttr),r.removeAttribute("sizes")),d&&i.setAttribute("data-optimumx",d),n&&i.setAttribute("data-ratio",n),s.appendChild(i),r.appendChild(s),setTimeout(function(){c.loader.unveil(o),c.rAF(function(){c.fire(o,"_lazyloaded",{},!0,!0),o.complete&&m({target:o})})}))}),z.addEventListener("load",m,!0),e.addEventListener("lazybeforesizes",function(e){var t,a,r,i;e.detail.instance==c&&e.target._lazybgset&&e.detail.dataAttr&&(t=e.target._lazybgset,r=t,i=(getComputedStyle(r)||{getPropertyValue:function(){}}).getPropertyValue("background-size"),!s[i]&&s[r.style.backgroundSize]&&(i=r.style.backgroundSize),s[a=i]&&(e.target._lazysizesParentFit=a,c.rAF(function(){e.target.setAttribute("data-parent-fit",a),e.target._lazysizesParentFit&&delete e.target._lazysizesParentFit})))},!0),z.documentElement.addEventListener("lazybeforesizes",function(e){var t,a;!e.defaultPrevented&&e.target._lazybgset&&e.detail.instance==c&&(e.detail.width=(t=e.target._lazybgset,a=c.gW(t,t.parentNode),(!t._lazysizesWidth||a>t._lazysizesWidth)&&(t._lazysizesWidth=a),t._lazysizesWidth))}))}); -------------------------------------------------------------------------------- /plugins/blur-up/README.md: -------------------------------------------------------------------------------- 1 | # The lazysizes Blur Up/effect plugin 2 | 3 | The lazysizes Blur Up plugin ([demo](https://jsfiddle.net/trixta/v0oq0412/embedded/result/)) gives you the possibility to also lazyload the low quality placeholder and enables you to create a blur up/fade over effect. 4 | 5 | This way the low quality image placeholder technique is more appealing to the user. 6 | 7 | ```js 8 | // never try to import *.min.js files 9 | import lazySizes from 'lazysizes'; 10 | import 'lazysizes/plugins/blur-up/ls.blur-up'; 11 | ``` 12 | 13 | ## How to 14 | 15 | Simply add a `data-lowsrc` attribute with the low quality image placeholder image to your `img` and in case of `picture` to your `source` elements. 16 | 17 | Lazysizes will then create a new image right after your original image with the following class `ls-blur-up-img`. 18 | 19 | The new image (`.ls-blur-up-img`) will get the following state classes to enable you to write a custom CSS animation/transition as soon as the image is in view and loaded: `ls-inview`/`ls-original-loaded`, while your original `img` gets the class `.ls-blur-up-is-loading` until the `.ls-blur-up-img` is loaded. 20 | 21 | 22 | ```html 23 | 69 |
70 |
71 | 78 |
79 |
80 | 81 | 82 | 83 | 84 | 85 | ``` 86 | 87 | 88 | ### Blur-up options 89 | 90 | #### BlurUp Mode 91 | 92 | The effect mode has two possible value: `"always"` (default: The effect is generated always) and `"auto"` (The effect is only used with non cached images). 93 | 94 | The blur up mode can be configured using JS or CSS: 95 | 96 | ```js 97 | import lazysizes from 'lazysizes'; 98 | import 'lazysizes/plugins/blur-up/ls.blur-up'; 99 | 100 | lazysizes.cfg.blurupMode = 'auto'; 101 | ``` 102 | 103 | ```css 104 | .mediabox-img { 105 | font-family: "blur-up: auto", "object-fit: cover"; 106 | } 107 | ``` 108 | 109 | #### You can override blur-up classes 110 | 111 | ```js 112 | import lazysizes from 'lazysizes'; 113 | import 'lazysizes/plugins/blur-up/ls.blur-up'; 114 | 115 | 116 | lazySizes.cfg.blurUpClass = 'blurred-image' 117 | ``` 118 | Here the list of override classes: 119 | 120 | * ``lazySizes.cfg.blurUpLoadingClass`` ls-blur-up-is-loading 121 | * ``lazySizes.cfg.blurUpInviewClass`` ls-inview 122 | * ``lazySizes.cfg.blurUpLoadedClass`` ls-blur-up-loaded 123 | * ``lazySizes.cfg.blurUpLoadedOriginalClass`` ls-original-loaded 124 | -------------------------------------------------------------------------------- /plugins/blur-up/ls.blur-up.js: -------------------------------------------------------------------------------- 1 | (function(window, factory) { 2 | if(!window) {return;} 3 | var globalInstall = function(){ 4 | factory(window.lazySizes); 5 | window.removeEventListener('lazyunveilread', globalInstall, true); 6 | }; 7 | 8 | factory = factory.bind(null, window, window.document); 9 | 10 | if(typeof module == 'object' && module.exports){ 11 | factory(require('lazysizes')); 12 | } else if (typeof define == 'function' && define.amd) { 13 | define(['lazysizes'], factory); 14 | } else if(window.lazySizes) { 15 | globalInstall(); 16 | } else { 17 | window.addEventListener('lazyunveilread', globalInstall, true); 18 | } 19 | }(typeof window != 'undefined' ? 20 | window : 0, function(window, document, lazySizes) { 21 | 'use strict'; 22 | 23 | var lazySizesCfg; 24 | 25 | (function(){ 26 | var prop; 27 | 28 | var blurUpDefaults = { 29 | blurUpClass: 'ls-blur-up-img', 30 | blurUpLoadingClass: 'ls-blur-up-is-loading', 31 | blurUpInviewClass: 'ls-inview', 32 | blurUpLoadedClass: 'ls-blur-up-loaded', 33 | blurUpLoadedOriginalClass: 'ls-original-loaded' 34 | }; 35 | 36 | lazySizesCfg = lazySizes.cfg || {}; 37 | 38 | for(prop in blurUpDefaults){ 39 | if(!(prop in lazySizesCfg)){ 40 | lazySizesCfg[prop] = blurUpDefaults[prop]; 41 | } 42 | } 43 | })(); 44 | 45 | var slice = [].slice; 46 | var regBlurUp = /blur-up["']*\s*:\s*["']*(always|auto)/; 47 | var regType = /image\/(jpeg|png|gif|svg\+xml)/; 48 | var transSrc = 'data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw=='; 49 | 50 | var matchesMedia = function (source) { 51 | var media = source.getAttribute('data-media') || source.getAttribute('media'); 52 | var type = source.getAttribute('type'); 53 | 54 | return (!type || regType.test(type)) && (!media || window.matchMedia(lazySizes.cfg.customMedia[media] || media).matches); 55 | }; 56 | 57 | var getLowSrc = function (picture, img) { 58 | var matchingLowSrc; 59 | var sources = picture ? slice.call(picture.querySelectorAll('source, img')) : [img]; 60 | 61 | sources.forEach(function (src) { 62 | if (matchingLowSrc) {return;} 63 | var lowSrc = src.getAttribute('data-lowsrc'); 64 | 65 | if (lowSrc && matchesMedia(src)) { 66 | matchingLowSrc = lowSrc; 67 | } 68 | }); 69 | 70 | return matchingLowSrc; 71 | }; 72 | 73 | var createBlurup = function(picture, img, src, blurUp){ 74 | var blurImg; 75 | var isBlurUpLoaded = false; 76 | var isForced = false; 77 | var start = blurUp == 'always' ? 0 : Date.now(); 78 | var isState = 0; 79 | var parent = (picture || img).parentNode; 80 | 81 | var createBlurUpImg = function () { 82 | 83 | if(!src){return;} 84 | 85 | var onloadBlurUp = function(e){ 86 | isBlurUpLoaded = true; 87 | 88 | if (!blurImg) { 89 | blurImg = e.target; 90 | } 91 | 92 | lazySizes.rAF(function () { 93 | lazySizes.rC(img, lazySizes.cfg.blurUpLoadingClass); 94 | if(blurImg) { 95 | lazySizes.aC(blurImg, lazySizes.cfg.blurUpLoadedClass); 96 | } 97 | }); 98 | 99 | if(blurImg){ 100 | blurImg.removeEventListener('load', onloadBlurUp); 101 | blurImg.removeEventListener('error', onloadBlurUp); 102 | } 103 | }; 104 | 105 | blurImg = document.createElement('img'); 106 | 107 | blurImg.addEventListener('load', onloadBlurUp); 108 | blurImg.addEventListener('error', onloadBlurUp); 109 | 110 | blurImg.className = lazySizes.cfg.blurUpClass; 111 | blurImg.cssText = img.cssText; 112 | blurImg.src = src; 113 | blurImg.alt = ''; 114 | blurImg.setAttribute('aria-hidden', 'true'); 115 | 116 | parent.insertBefore(blurImg, (picture || img).nextSibling); 117 | 118 | if(blurUp != 'always'){ 119 | blurImg.style.visibility = 'hidden'; 120 | 121 | lazySizes.rAF(function () { 122 | if (blurImg) { 123 | setTimeout(function(){ 124 | if (blurImg) { 125 | lazySizes.rAF(function () { 126 | if(!isForced && blurImg){ 127 | blurImg.style.visibility = ''; 128 | } 129 | }); 130 | } 131 | }, lazySizes.cfg.blurupCacheDelay || 33); 132 | } 133 | }); 134 | } 135 | }; 136 | 137 | var remove = function () { 138 | if(blurImg){ 139 | lazySizes.rAF(function() { 140 | lazySizes.rC(img, lazySizes.cfg.blurUpLoadingClass); 141 | try { 142 | blurImg.parentNode.removeChild(blurImg); 143 | } catch(er){} 144 | blurImg = null; 145 | }); 146 | } 147 | }; 148 | 149 | var setStateUp = function(force){ 150 | isState++; 151 | 152 | isForced = force || isForced; 153 | 154 | if(force){ 155 | remove(); 156 | } else if(isState > 1) { 157 | setTimeout(remove, 5000); 158 | } 159 | }; 160 | 161 | var onload = function() { 162 | img.removeEventListener('load', onload); 163 | img.removeEventListener('error', onload); 164 | 165 | if(blurImg){ 166 | lazySizes.rAF(function(){ 167 | if(blurImg) { 168 | lazySizes.aC(blurImg, lazySizes.cfg.blurUpLoadedOriginalClass); 169 | } 170 | }); 171 | } 172 | 173 | lazySizes.fire(img, 'blurUpLoaded'); 174 | 175 | if(blurUp != 'always' && (!isBlurUpLoaded || Date.now() - start < 66)){ 176 | setStateUp(true); 177 | } else { 178 | setStateUp(); 179 | } 180 | }; 181 | 182 | createBlurUpImg(); 183 | 184 | img.addEventListener('load', onload); 185 | img.addEventListener('error', onload); 186 | 187 | lazySizes.aC(img, lazySizes.cfg.blurUpLoadingClass); 188 | 189 | var parentUnveil = function (e) { 190 | if(parent != e.target){ 191 | return; 192 | } 193 | 194 | lazySizes.aC(blurImg || img, lazySizes.cfg.blurUpInviewClass); 195 | 196 | setStateUp(); 197 | 198 | parent.removeEventListener('lazybeforeunveil', parentUnveil); 199 | }; 200 | 201 | if(!parent.getAttribute('data-expand')){ 202 | parent.setAttribute('data-expand', -1); 203 | } 204 | 205 | parent.addEventListener('lazybeforeunveil', parentUnveil); 206 | 207 | lazySizes.aC(parent, lazySizes.cfg.lazyClass); 208 | 209 | }; 210 | 211 | window.addEventListener('lazybeforeunveil', function (e) { 212 | var detail = e.detail; 213 | 214 | if(detail.instance != lazySizes || !detail.blurUp){return;} 215 | 216 | var img = e.target; 217 | var picture = img.parentNode; 218 | 219 | if(picture.nodeName != 'PICTURE'){ 220 | picture = null; 221 | } 222 | 223 | createBlurup(picture, img, getLowSrc(picture, img) || transSrc, detail.blurUp); 224 | }); 225 | 226 | window.addEventListener('lazyunveilread', function (e) { 227 | var detail = e.detail; 228 | 229 | if(detail.instance != lazySizes){return;} 230 | 231 | var img = e.target; 232 | var match = (getComputedStyle(img, null) || {fontFamily: ''}).fontFamily.match(regBlurUp); 233 | 234 | if(!match && !img.getAttribute('data-lowsrc')){return;} 235 | 236 | detail.blurUp = match && match[1] || lazySizes.cfg.blurupMode || 'always'; 237 | }); 238 | })); 239 | -------------------------------------------------------------------------------- /plugins/blur-up/ls.blur-up.min.js: -------------------------------------------------------------------------------- 1 | /*! lazysizes - v5.3.2 */ 2 | 3 | !function(e,t){var a;e&&(a=function(){t(e.lazySizes),e.removeEventListener("lazyunveilread",a,!0)},t=t.bind(null,e,e.document),"object"==typeof module&&module.exports?t(require("lazysizes")):"function"==typeof define&&define.amd?define(["lazysizes"],t):e.lazySizes?a():e.addEventListener("lazyunveilread",a,!0))}("undefined"!=typeof window?window:0,function(l,b,A){"use strict";var a;!function(){var e,t={blurUpClass:"ls-blur-up-img",blurUpLoadingClass:"ls-blur-up-is-loading",blurUpInviewClass:"ls-inview",blurUpLoadedClass:"ls-blur-up-loaded",blurUpLoadedOriginalClass:"ls-original-loaded"};for(e in a=A.cfg||{},t)e in a||(a[e]=t[e])}();function r(e,t){var i;return(e?n.call(e.querySelectorAll("source, img")):[t]).forEach(function(e){var t,a,n,r;i||(!(t=e.getAttribute("data-lowsrc"))||(n=(a=e).getAttribute("data-media")||a.getAttribute("media"),(r=a.getAttribute("type"))&&!o.test(r)||n&&!l.matchMedia(A.cfg.customMedia[n]||n).matches)||(i=t))}),i}function i(e,t,a,n){function r(){l&&A.rAF(function(){A.rC(t,A.cfg.blurUpLoadingClass);try{l.parentNode.removeChild(l)}catch(e){}l=null})}function i(e){c++,u=e||u,e?r():1 source"`` elements using the ``customMedia`` option of lazySizes. 4 | 5 | ## Configuration via CSS 6 | 7 | The following CSS... 8 | 9 | ```css 10 | html:after { 11 | display: none; 12 | content: '--small: (max-width: 500px) | --medium: (max-width: 1100px) | --large: (max-width: 1500px)'; 13 | } 14 | ``` 15 | 16 | ... allows you to write the following markup: 17 | 18 | ```html 19 | 20 | 21 | 24 | 27 | 30 | 31 | image with artdirection 36 | 37 | ``` 38 | 39 | The parsed custom media query object can be accessed through the ``lazySizesConfig.customMedia`` option object: 40 | 41 | ```js 42 | window.lazySizesConfig.customMedia; // returns: 43 | 44 | /* 45 | { 46 | '--small': '(max-width: 500px)', 47 | '--medium': (min-width: 1100px)', 48 | '--large': '(max-width: 1100px)' 49 | } 50 | */ 51 | ``` 52 | 53 | ```scss 54 | /* 55 | Simple Sass mixin to share a map of breakpoints between CSS and JS 56 | Usage: 57 | $breakpoints: ( 58 | --small: (max-width: 480px), 59 | --medium: (max-width: 1024px), 60 | --large: (min-width: 1280px) 61 | ); 62 | 63 | html:after { 64 | @include shareBreakpoints($breakpoints); 65 | } 66 | */ 67 | @mixin shareBreakpoints($map , $cssprop: content){ 68 | $description: ''; 69 | 70 | @each $property, $value in $map 71 | { 72 | @if $description != '' { 73 | $description: $description + ' | '; 74 | } 75 | $description: $description + $property +': '+ inspect($value); 76 | } 77 | 78 | display: none; 79 | #{$cssprop}: $description; 80 | } 81 | ``` 82 | 83 | 84 | -------------------------------------------------------------------------------- /plugins/custommedia/ls.custommedia.js: -------------------------------------------------------------------------------- 1 | /* 2 | html:after { 3 | display: none; 4 | content: '--small: (max-width: 500px) | --medium: (max-width: 1100px) | --large: (min-width: 1100px)'; 5 | } 6 | */ 7 | (function(window, factory) { 8 | var globalInstall = function(){ 9 | factory(window.lazySizes); 10 | window.removeEventListener('lazyunveilread', globalInstall, true); 11 | }; 12 | 13 | factory = factory.bind(null, window, window.document); 14 | 15 | if(typeof module == 'object' && module.exports){ 16 | factory(require('lazysizes')); 17 | } else if (typeof define == 'function' && define.amd) { 18 | define(['lazysizes'], factory); 19 | } else if(window.lazySizes) { 20 | globalInstall(); 21 | } else { 22 | window.addEventListener('lazyunveilread', globalInstall, true); 23 | } 24 | }(window, function(window, document, lazySizes) { 25 | /*jshint eqnull:true */ 26 | 'use strict'; 27 | var docElem = document.documentElement; 28 | 29 | lazySizes.getCustomMedias = (function(){ 30 | var regCleanPseudos = /['"]/g; 31 | var regSplit = /\s*\|\s*/g; 32 | var regNamedQueries = /^([a-z0-9_-]+)\s*:\s*(.+)$/i; 33 | 34 | var getStyle = function(elem, pseudo){ 35 | return ((getComputedStyle(elem, pseudo) || {getPropertyValue: function(){}}).getPropertyValue('content') || 'none').replace(regCleanPseudos, '').trim(); 36 | }; 37 | var parse = function(string, object){ 38 | string.split(regSplit).forEach(function(query){ 39 | var match = query.match(regNamedQueries); 40 | 41 | if(match){ 42 | object[match[1]] = match[2]; 43 | } 44 | }); 45 | }; 46 | return function(object, element){ 47 | object = object || lazySizes.cfg.customMedia; 48 | element = element || document.querySelector('html'); 49 | parse(getStyle(element, ':before'), object); 50 | parse(getStyle(element, ':after'), object); 51 | return object; 52 | }; 53 | })(); 54 | 55 | lazySizes.updateCustomMedia = function(){ 56 | var i, len, customMedia; 57 | var elems = docElem.querySelectorAll('source[media][data-media][srcset]'); 58 | 59 | lazySizes.getCustomMedias(); 60 | 61 | for(i = 0, len = elems.length; i < len; i++){ 62 | if( (customMedia = lazySizes.cfg.customMedia[elems[i].getAttribute('data-media') || elems[i].getAttribute('media')]) ){ 63 | elems[i].setAttribute('media', customMedia); 64 | } 65 | } 66 | 67 | elems = docElem.querySelector('source[media][data-media][srcset] ~ img'); 68 | for(i = 0, len = elems.length; i < len; i++){ 69 | lazySizes.uP(elems[i]); 70 | } 71 | 72 | lazySizes.autoSizer.checkElems(); 73 | }; 74 | 75 | lazySizes.getCustomMedias(); 76 | 77 | })); 78 | -------------------------------------------------------------------------------- /plugins/custommedia/ls.custommedia.min.js: -------------------------------------------------------------------------------- 1 | /*! lazysizes - v5.3.2 */ 2 | 3 | !function(e,t){var i=function(){t(e.lazySizes),e.removeEventListener("lazyunveilread",i,!0)};t=t.bind(null,e,e.document),"object"==typeof module&&module.exports?t(require("lazysizes")):"function"==typeof define&&define.amd?define(["lazysizes"],t):e.lazySizes?i():e.addEventListener("lazyunveilread",i,!0)}(window,function(e,i,a){"use strict";var n,t,r,o=i.documentElement;function u(e,t){return((getComputedStyle(e,t)||{getPropertyValue:function(){}}).getPropertyValue("content")||"none").replace(n,"").trim()}function s(e,i){e.split(t).forEach(function(e){var t=e.match(r);t&&(i[t[1]]=t[2])})}a.getCustomMedias=(n=/['"]/g,t=/\s*\|\s*/g,r=/^([a-z0-9_-]+)\s*:\s*(.+)$/i,function(e,t){return e=e||a.cfg.customMedia,t=t||i.querySelector("html"),s(u(t,":before"),e),s(u(t,":after"),e),e}),a.updateCustomMedia=function(){var e,t,i,n=o.querySelectorAll("source[media][data-media][srcset]");for(a.getCustomMedias(),e=0,t=n.length;e 15 | */ 16 | 17 | (function(window, factory) { 18 | var globalInstall = function(){ 19 | factory(window.lazySizes); 20 | window.removeEventListener('lazyunveilread', globalInstall, true); 21 | }; 22 | 23 | factory = factory.bind(null, window, window.document); 24 | 25 | if(typeof module == 'object' && module.exports){ 26 | factory(require('lazysizes')); 27 | } else if (typeof define == 'function' && define.amd) { 28 | define(['lazysizes'], factory); 29 | } else if(window.lazySizes) { 30 | globalInstall(); 31 | } else { 32 | window.addEventListener('lazyunveilread', globalInstall, true); 33 | } 34 | }(window, function(window, document, lazySizes) { 35 | 'use strict'; 36 | var regPicture; 37 | var lazySizesCfg = lazySizes.cfg; 38 | var img = document.createElement('img'); 39 | 40 | if(('srcset' in img) && !('sizes' in img) && !window.HTMLPictureElement){ 41 | regPicture = /^picture$/i; 42 | document.addEventListener('lazybeforeunveil', function(e){ 43 | if(e.detail.instance != lazySizes){return;} 44 | 45 | var elem, parent, srcset, sizes, isPicture; 46 | var picture, source; 47 | if(e.defaultPrevented || 48 | lazySizesCfg.noIOSFix || 49 | !(elem = e.target) || 50 | !(srcset = elem.getAttribute(lazySizesCfg.srcsetAttr)) || 51 | !(parent = elem.parentNode) || 52 | ( 53 | !(isPicture = regPicture.test(parent.nodeName || '')) && 54 | !(sizes = elem.getAttribute('sizes') || elem.getAttribute(lazySizesCfg.sizesAttr)) 55 | ) 56 | ){return;} 57 | 58 | picture = isPicture ? parent : document.createElement('picture'); 59 | 60 | if(!elem._lazyImgSrc){ 61 | Object.defineProperty(elem, '_lazyImgSrc', { 62 | value: document.createElement('source'), 63 | writable: true 64 | }); 65 | } 66 | source = elem._lazyImgSrc; 67 | 68 | if(sizes){ 69 | source.setAttribute('sizes', sizes); 70 | } 71 | 72 | source.setAttribute(lazySizesCfg.srcsetAttr, srcset); 73 | elem.setAttribute('data-pfsrcset', srcset); 74 | elem.removeAttribute(lazySizesCfg.srcsetAttr); 75 | 76 | if(!isPicture){ 77 | parent.insertBefore(picture, elem); 78 | picture.appendChild(elem); 79 | } 80 | picture.insertBefore(source, elem); 81 | }); 82 | } 83 | })); 84 | -------------------------------------------------------------------------------- /plugins/fix-ios-sizes/fix-ios-sizes.min.js: -------------------------------------------------------------------------------- 1 | /*! lazysizes - v5.3.2 */ 2 | 3 | !function(e,t){var r=function(){t(e.lazySizes),e.removeEventListener("lazyunveilread",r,!0)};t=t.bind(null,e,e.document),"object"==typeof module&&module.exports?t(require("lazysizes")):"function"==typeof define&&define.amd?define(["lazysizes"],t):e.lazySizes?r():e.addEventListener("lazyunveilread",r,!0)}(window,function(e,c,l){"use strict";var d,o=l.cfg,t=c.createElement("img");!("srcset"in t)||"sizes"in t||e.HTMLPictureElement||(d=/^picture$/i,c.addEventListener("lazybeforeunveil",function(e){var t,r,i,n,s,a,u;e.detail.instance==l&&!e.defaultPrevented&&!o.noIOSFix&&(t=e.target)&&(i=t.getAttribute(o.srcsetAttr))&&(r=t.parentNode)&&((s=d.test(r.nodeName||""))||(n=t.getAttribute("sizes")||t.getAttribute(o.sizesAttr)))&&(a=s?r:c.createElement("picture"),t._lazyImgSrc||Object.defineProperty(t,"_lazyImgSrc",{value:c.createElement("source"),writable:!0}),u=t._lazyImgSrc,n&&u.setAttribute("sizes",n),u.setAttribute(o.srcsetAttr,i),t.setAttribute("data-pfsrcset",i),t.removeAttribute(o.srcsetAttr),s||(r.insertBefore(a,t),a.appendChild(t)),a.insertBefore(u,t))}))}); -------------------------------------------------------------------------------- /plugins/include/ls.include.min.js: -------------------------------------------------------------------------------- 1 | /*! lazysizes - v5.3.2 */ 2 | 3 | !function(e,n){var t=function(){n(e.lazySizes),e.removeEventListener("lazyunveilread",t,!0)};n=n.bind(null,e,e.document),"object"==typeof module&&module.exports?n(require("lazysizes")):"function"==typeof define&&define.amd?define(["lazysizes"],n):e.lazySizes?t():e.addEventListener("lazyunveilread",t,!0)}(window,function(a,o,L){"use strict";var s,l,r,d,c,u,f,t,m,y,h,i,p,T,e,v,g,z,E,M,n,C,q;function b(){E.length&&(g=0,E.d())}function S(){for(var e=0,n=i.length;e 26 | ``` 27 | 28 | ## `nativeLoading` Options 29 | 30 | Options are changed at the `lazySizes.cfg.nativeLoading` options object: 31 | 32 | ```js 33 | import lazySizes from 'lazysizes'; 34 | import 'lazysizes/plugins/native-loading/ls.native-loading'; 35 | 36 | lazySizes.cfg.nativeLoading = { 37 | setLoadingAttribute: true, 38 | disableListeners: { 39 | scroll: true 40 | }, 41 | }; 42 | ``` 43 | 44 | ### `setLoadingAttribute` `boolean` option 45 | 46 | By setting `setLoadingAttribute` to `true`. LazySizes will automatically set the `loading="lazy"` attribute for you. ` 47 | 48 | This way all `img`/`iframe` elements will natively lazyloaded without any changes to your normal lazySizes markup. 49 | 50 | ### `disableListeners` `boolean`/`eventMap` 51 | 52 | Due to the fact that you can use lazySizes for many things. Native lazy loading does not remove any event listeners automatically. 53 | 54 | By setting `disableListeners` to `true` all events listeners are removed. Often it makes sense to only remove specific events like the scroll event for example. 55 | 56 | The possible full event map looks like this: 57 | 58 | ```html 59 | { 60 | focus: true, 61 | mouseover: true, 62 | click: true, 63 | load: true, 64 | transitionend: true, 65 | animationend: true, 66 | scroll: true, 67 | resize: true, 68 | } 69 | ``` 70 | -------------------------------------------------------------------------------- /plugins/native-loading/ls.native-loading.js: -------------------------------------------------------------------------------- 1 | (function(window, factory) { 2 | var globalInstall = function(){ 3 | factory(window.lazySizes); 4 | window.removeEventListener('lazyunveilread', globalInstall, true); 5 | }; 6 | 7 | factory = factory.bind(null, window, window.document); 8 | 9 | if(typeof module == 'object' && module.exports){ 10 | factory(require('lazysizes')); 11 | } else if (typeof define == 'function' && define.amd) { 12 | define(['lazysizes'], factory); 13 | } else if(window.lazySizes) { 14 | globalInstall(); 15 | } else { 16 | window.addEventListener('lazyunveilread', globalInstall, true); 17 | } 18 | }(window, function(window, document, lazySizes) { 19 | 'use strict'; 20 | 21 | var imgSupport = 'loading' in HTMLImageElement.prototype; 22 | var iframeSupport = 'loading' in HTMLIFrameElement.prototype; 23 | var isConfigSet = false; 24 | var oldPrematureUnveil = lazySizes.prematureUnveil; 25 | var cfg = lazySizes.cfg; 26 | var listenerMap = { 27 | focus: 1, 28 | mouseover: 1, 29 | click: 1, 30 | load: 1, 31 | transitionend: 1, 32 | animationend: 1, 33 | scroll: 1, 34 | resize: 1, 35 | }; 36 | 37 | if (!cfg.nativeLoading) { 38 | cfg.nativeLoading = {}; 39 | } 40 | 41 | if (!window.addEventListener || !window.MutationObserver || (!imgSupport && !iframeSupport)) { 42 | return; 43 | } 44 | 45 | function disableEvents() { 46 | var loader = lazySizes.loader; 47 | var throttledCheckElements = loader.checkElems; 48 | var removeALSL = function(){ 49 | setTimeout(function(){ 50 | window.removeEventListener('scroll', loader._aLSL, true); 51 | }, 1000); 52 | }; 53 | var currentListenerMap = typeof cfg.nativeLoading.disableListeners == 'object' ? 54 | cfg.nativeLoading.disableListeners : 55 | listenerMap; 56 | 57 | if (currentListenerMap.scroll) { 58 | window.addEventListener('load', removeALSL); 59 | removeALSL(); 60 | 61 | window.removeEventListener('scroll', throttledCheckElements, true); 62 | } 63 | 64 | if (currentListenerMap.resize) { 65 | window.removeEventListener('resize', throttledCheckElements, true); 66 | } 67 | 68 | Object.keys(currentListenerMap).forEach(function(name) { 69 | if (currentListenerMap[name]) { 70 | document.removeEventListener(name, throttledCheckElements, true); 71 | } 72 | }); 73 | } 74 | 75 | function runConfig() { 76 | if (isConfigSet) {return;} 77 | isConfigSet = true; 78 | 79 | if (imgSupport && iframeSupport && cfg.nativeLoading.disableListeners) { 80 | if (cfg.nativeLoading.disableListeners === true) { 81 | cfg.nativeLoading.setLoadingAttribute = true; 82 | } 83 | 84 | disableEvents(); 85 | } 86 | 87 | if (cfg.nativeLoading.setLoadingAttribute) { 88 | window.addEventListener('lazybeforeunveil', function(e){ 89 | var element = e.target; 90 | 91 | if ('loading' in element && !element.getAttribute('loading')) { 92 | element.setAttribute('loading', 'lazy'); 93 | } 94 | }, true); 95 | } 96 | } 97 | 98 | lazySizes.prematureUnveil = function prematureUnveil(element) { 99 | 100 | if (!isConfigSet) { 101 | runConfig(); 102 | } 103 | 104 | if ('loading' in element && 105 | (cfg.nativeLoading.setLoadingAttribute || element.getAttribute('loading')) && 106 | (element.getAttribute('data-sizes') != 'auto' || element.offsetWidth)) { 107 | return true; 108 | } 109 | 110 | if (oldPrematureUnveil) { 111 | return oldPrematureUnveil(element); 112 | } 113 | }; 114 | 115 | })); 116 | -------------------------------------------------------------------------------- /plugins/native-loading/ls.native-loading.min.js: -------------------------------------------------------------------------------- 1 | /*! lazysizes - v5.3.2 */ 2 | 3 | !function(e,t){var n=function(){t(e.lazySizes),e.removeEventListener("lazyunveilread",n,!0)};t=t.bind(null,e,e.document),"object"==typeof module&&module.exports?t(require("lazysizes")):"function"==typeof define&&define.amd?define(["lazysizes"],t):e.lazySizes?n():e.addEventListener("lazyunveilread",n,!0)}(window,function(a,o,r){"use strict";var s="loading"in HTMLImageElement.prototype,d="loading"in HTMLIFrameElement.prototype,l=!1,t=r.prematureUnveil,v=r.cfg,u={focus:1,mouseover:1,click:1,load:1,transitionend:1,animationend:1,scroll:1,resize:1};function n(){var e,t,n;function i(){setTimeout(function(){a.removeEventListener("scroll",e._aLSL,!0)},1e3)}l||(l=!0,s&&d&&v.nativeLoading.disableListeners&&(!0===v.nativeLoading.disableListeners&&(v.nativeLoading.setLoadingAttribute=!0),e=r.loader,t=e.checkElems,(n="object"==typeof v.nativeLoading.disableListeners?v.nativeLoading.disableListeners:u).scroll&&(a.addEventListener("load",i),i(),a.removeEventListener("scroll",t,!0)),n.resize&&a.removeEventListener("resize",t,!0),Object.keys(n).forEach(function(e){n[e]&&o.removeEventListener(e,t,!0)})),v.nativeLoading.setLoadingAttribute&&a.addEventListener("lazybeforeunveil",function(e){var t=e.target;"loading"in t&&!t.getAttribute("loading")&&t.setAttribute("loading","lazy")},!0))}v.nativeLoading||(v.nativeLoading={}),a.addEventListener&&a.MutationObserver&&(s||d)&&(r.prematureUnveil=function(e){return l||n(),!(!("loading"in e&&(v.nativeLoading.setLoadingAttribute||e.getAttribute("loading")))||"auto"==e.getAttribute("data-sizes")&&!e.offsetWidth)||(t?t(e):void 0)})}); -------------------------------------------------------------------------------- /plugins/noscript/README.md: -------------------------------------------------------------------------------- 1 | # lazysizes noscript/progressive enhancement extension 2 | 3 | The noscript extension is the true ultimate progressive enhancement extension for lazySizes. It allows you to transform any HTML inside a ``noscript`` element as soon as it becomes visible. 4 | 5 | ## Markup 6 | 7 | The ``lazyload`` class has to be added to the parent element of the ``noscript`` element and this element has to also have a ``data-noscript`` attribute. As soon as it is near the viewport the content of the ``noscript`` element will replace the content of the ``.lazyload` element. 8 | 9 | ```html 10 |
11 | 14 |
15 | 16 | 17 | 18 |
19 | 45 |
46 | ``` 47 | 48 | **Important note**: While you also can transform responsive images with this plugin, neither the ``data-sizes`` nor the ``customMedia`` features do work with the ``noscript`` extension. Also note: Android 2.x is not supported with this plugin. 49 | 50 | ## Troubleshooting: Escaped HTML entities 51 | Normally the content of a ``noscript`` must be retrieved as text. But in some cases for example, if the ``noscript`` element was created in a XML documented/context, it must be retrieved as HTML. This can't be automatically detected. 52 | 53 | In case this happens, you can fix this either by making sure that ``noscript`` elements are always created in a *text/html* context or by overriding the ``getNoscriptContent`` option callback: 54 | 55 | ```js 56 | window.lazySizesConfig = window.lazySizesConfig || {}; 57 | 58 | window.lazySizesConfig.getNoscriptContent = function(noScript){ 59 | return (noScript.isXML) ? noScript.innerHTML : (noScript.textContent || noScript.innerText); 60 | }; 61 | ``` 62 | 63 | ## Add IE8- support with conditional comments 64 | The noscript extension can also be used in conjunction with conditional comments to add progressive enhancement support for IE8-: 65 | 66 | ```html 67 |
68 | 69 |

any kind of content you want to be unveiled

70 | 71 |
72 | ``` 73 | -------------------------------------------------------------------------------- /plugins/noscript/ls.noscript.js: -------------------------------------------------------------------------------- 1 | (function(window, factory) { 2 | var globalInstall = function(){ 3 | factory(window.lazySizes); 4 | window.removeEventListener('lazyunveilread', globalInstall, true); 5 | }; 6 | 7 | factory = factory.bind(null, window, window.document); 8 | 9 | if(typeof module == 'object' && module.exports){ 10 | factory(require('lazysizes')); 11 | } else if (typeof define == 'function' && define.amd) { 12 | define(['lazysizes'], factory); 13 | } else if(window.lazySizes) { 14 | globalInstall(); 15 | } else { 16 | window.addEventListener('lazyunveilread', globalInstall, true); 17 | } 18 | }(window, function(window, document, lazySizes) { 19 | /*jshint eqnull:true */ 20 | 'use strict'; 21 | 22 | var dummyParent = {nodeName: ''}; 23 | var supportPicture = !!window.HTMLPictureElement && ('sizes' in document.createElement('img')); 24 | var config = window.lazySizes && lazySizes.cfg; 25 | 26 | var handleLoadingElements = function(e){ 27 | var i, isResponsive, hasTriggered, onload, loading; 28 | 29 | var loadElements = e.target.querySelectorAll('img, iframe'); 30 | 31 | for(i = 0; i < loadElements.length; i++){ 32 | isResponsive = loadElements[i].getAttribute('srcset') || (loadElements[i].parentNode || dummyParent).nodeName.toLowerCase() == 'picture'; 33 | 34 | if(!supportPicture && isResponsive){ 35 | lazySizes.uP(loadElements[i]); 36 | } 37 | 38 | if(!loadElements[i].complete && (isResponsive || loadElements[i].src)){ 39 | e.detail.firesLoad = true; 40 | 41 | if(!onload || !loading){ 42 | loading = 0; 43 | /*jshint loopfunc:true */ 44 | onload = function(evt){ 45 | loading--; 46 | if((!evt || loading < 1) && !hasTriggered){ 47 | hasTriggered = true; 48 | e.detail.firesLoad = false; 49 | lazySizes.fire(e.target, '_lazyloaded', {}, false, true); 50 | } 51 | 52 | if(evt && evt.target){ 53 | evt.target.removeEventListener('load', onload); 54 | evt.target.removeEventListener('error', onload); 55 | } 56 | }; 57 | 58 | setTimeout(onload, 3500); 59 | } 60 | 61 | loading++; 62 | 63 | loadElements[i].addEventListener('load', onload); 64 | loadElements[i].addEventListener('error', onload); 65 | } 66 | } 67 | }; 68 | 69 | config.getNoscriptContent = function(noScript){ 70 | return noScript.textContent || noScript.innerText; 71 | }; 72 | 73 | window.addEventListener('lazybeforeunveil', function(e){ 74 | if(e.detail.instance != lazySizes || e.defaultPrevented || e.target.getAttribute('data-noscript') == null){return;} 75 | 76 | var noScript = e.target.querySelector('noscript, script[type*="html"]') || {}; 77 | var content = config.getNoscriptContent(noScript); 78 | 79 | if(content){ 80 | e.target.innerHTML = content; 81 | handleLoadingElements(e); 82 | } 83 | }); 84 | })); 85 | -------------------------------------------------------------------------------- /plugins/noscript/ls.noscript.min.js: -------------------------------------------------------------------------------- 1 | /*! lazysizes - v5.3.2 */ 2 | 3 | !function(e,t){var n=function(){t(e.lazySizes),e.removeEventListener("lazyunveilread",n,!0)};t=t.bind(null,e,e.document),"object"==typeof module&&module.exports?t(require("lazysizes")):"function"==typeof define&&define.amd?define(["lazysizes"],t):e.lazySizes?n():e.addEventListener("lazyunveilread",n,!0)}(window,function(e,t,d){"use strict";var l={nodeName:""},s=!!e.HTMLPictureElement&&"sizes"in t.createElement("img"),r=e.lazySizes&&d.cfg;r.getNoscriptContent=function(e){return e.textContent||e.innerText},e.addEventListener("lazybeforeunveil",function(e){var t,n;e.detail.instance!=d||e.defaultPrevented||null==e.target.getAttribute("data-noscript")||(t=e.target.querySelector('noscript, script[type*="html"]')||{},(n=r.getNoscriptContent(t))&&(e.target.innerHTML=n,function(t){for(var e,n,r,i,a=t.target.querySelectorAll("img, iframe"),o=0;o 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | ``` 21 | 22 | ```js 23 | // never try to import *.min.js files 24 | import lazySizes from 'lazysizes'; 25 | import 'lazysizes/plugins/parent-fit/ls.parent-fit'; 26 | 27 | // polyfills 28 | import 'lazysizes/plugins/respimg/ls.respimg'; 29 | 30 | if (!('object-fit' in document.createElement('a').style)) { 31 | require('lazysizes/plugins/object-fit/ls.object-fit'); 32 | } 33 | ``` 34 | 35 | ### Add markup 36 | The object-fit plugin is not a full polyfill. 37 | 38 | ```html 39 |
40 | 44 | /> 45 |
46 | 47 |
48 | 52 | /> 53 |
54 | ``` 55 | 56 | ### CSS 57 | 58 | To init the plugin on an image simply use the `font-family` property directly on your image. 59 | 60 | ```css 61 | .imagecontainer { 62 | position: relative; 63 | border: 3px solid #ccc; 64 | } 65 | 66 | .imagecontainer:before { 67 | display: block; 68 | width: 100%; 69 | content: ""; 70 | padding-bottom: 100%; 71 | height: 0; 72 | } 73 | 74 | .imagecontainer-img { 75 | position: absolute; 76 | display: block; 77 | top: 0; 78 | left: 0; 79 | width: 100%; 80 | height: 100%; 81 | transition: 400ms transform; 82 | 83 | object-fit: contain; 84 | font-family: "object-fit: contain"; 85 | } 86 | 87 | .imagecontainer-img:hover { 88 | transform: scale(1.1); 89 | } 90 | ``` 91 | -------------------------------------------------------------------------------- /plugins/object-fit/ls.object-fit.js: -------------------------------------------------------------------------------- 1 | (function(window, factory) { 2 | if(!window) {return;} 3 | var globalInstall = function(initialEvent){ 4 | factory(window.lazySizes, initialEvent); 5 | window.removeEventListener('lazyunveilread', globalInstall, true); 6 | }; 7 | 8 | factory = factory.bind(null, window, window.document); 9 | 10 | if(typeof module == 'object' && module.exports){ 11 | factory(require('lazysizes')); 12 | } else if (typeof define == 'function' && define.amd) { 13 | define(['lazysizes'], factory); 14 | } else if(window.lazySizes) { 15 | globalInstall(); 16 | } else { 17 | window.addEventListener('lazyunveilread', globalInstall, true); 18 | } 19 | }(typeof window != 'undefined' ? 20 | window : 0, function(window, document, lazySizes, initialEvent) { 21 | 'use strict'; 22 | var cloneElementClass; 23 | var style = document.createElement('a').style; 24 | var fitSupport = 'objectFit' in style; 25 | var positionSupport = fitSupport && 'objectPosition' in style; 26 | var regCssFit = /object-fit["']*\s*:\s*["']*(contain|cover)/; 27 | var regCssPosition = /object-position["']*\s*:\s*["']*(.+?)(?=($|,|'|"|;))/; 28 | var blankSrc = 'data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw=='; 29 | var regBgUrlEscape = /\(|\)|'/; 30 | var positionDefaults = { 31 | center: 'center', 32 | '50% 50%': 'center', 33 | }; 34 | 35 | function getObject(element){ 36 | var css = (getComputedStyle(element, null) || {}); 37 | var content = css.fontFamily || ''; 38 | var objectFit = content.match(regCssFit) || ''; 39 | var objectPosition = objectFit && content.match(regCssPosition) || ''; 40 | 41 | if(objectPosition){ 42 | objectPosition = objectPosition[1]; 43 | } 44 | 45 | return { 46 | fit: objectFit && objectFit[1] || '', 47 | position: positionDefaults[objectPosition] || objectPosition || 'center', 48 | }; 49 | } 50 | 51 | function generateStyleClass() { 52 | if (cloneElementClass) { 53 | return; 54 | } 55 | 56 | var styleElement = document.createElement('style'); 57 | 58 | cloneElementClass = lazySizes.cfg.objectFitClass || 'lazysizes-display-clone'; 59 | 60 | document.querySelector('head').appendChild(styleElement); 61 | } 62 | 63 | function removePrevClone(element) { 64 | var prev = element.previousElementSibling; 65 | 66 | if (prev && lazySizes.hC(prev, cloneElementClass)) { 67 | prev.parentNode.removeChild(prev); 68 | element.style.position = prev.getAttribute('data-position') || ''; 69 | element.style.visibility = prev.getAttribute('data-visibility') || ''; 70 | } 71 | } 72 | 73 | function initFix(element, config){ 74 | var switchClassesAdded, addedSrc, styleElement, styleElementStyle; 75 | var lazysizesCfg = lazySizes.cfg; 76 | 77 | var onChange = function(){ 78 | var src = element.currentSrc || element.src; 79 | 80 | if(src && addedSrc !== src){ 81 | addedSrc = src; 82 | styleElementStyle.backgroundImage = 'url(' + (regBgUrlEscape.test(src) ? JSON.stringify(src) : src ) + ')'; 83 | 84 | if(!switchClassesAdded){ 85 | switchClassesAdded = true; 86 | lazySizes.rC(styleElement, lazysizesCfg.loadingClass); 87 | lazySizes.aC(styleElement, lazysizesCfg.loadedClass); 88 | } 89 | } 90 | }; 91 | var rafedOnChange = function(){ 92 | lazySizes.rAF(onChange); 93 | }; 94 | 95 | element._lazysizesParentFit = config.fit; 96 | 97 | element.addEventListener('lazyloaded', rafedOnChange, true); 98 | element.addEventListener('load', rafedOnChange, true); 99 | 100 | lazySizes.rAF(function(){ 101 | 102 | var hideElement = element; 103 | var container = element.parentNode; 104 | 105 | if(container.nodeName.toUpperCase() == 'PICTURE'){ 106 | hideElement = container; 107 | container = container.parentNode; 108 | } 109 | 110 | removePrevClone(hideElement); 111 | 112 | if (!cloneElementClass) { 113 | generateStyleClass(); 114 | } 115 | 116 | styleElement = element.cloneNode(false); 117 | styleElementStyle = styleElement.style; 118 | 119 | styleElement.addEventListener('load', function(){ 120 | var curSrc = styleElement.currentSrc || styleElement.src; 121 | 122 | if(curSrc && curSrc != blankSrc){ 123 | styleElement.src = blankSrc; 124 | styleElement.srcset = ''; 125 | } 126 | }); 127 | 128 | lazySizes.rC(styleElement, lazysizesCfg.loadedClass); 129 | lazySizes.rC(styleElement, lazysizesCfg.lazyClass); 130 | lazySizes.rC(styleElement, lazysizesCfg.autosizesClass); 131 | lazySizes.aC(styleElement, lazysizesCfg.loadingClass); 132 | lazySizes.aC(styleElement, cloneElementClass); 133 | 134 | ['data-parent-fit', 'data-parent-container', 'data-object-fit-polyfilled', 135 | lazysizesCfg.srcsetAttr, lazysizesCfg.srcAttr].forEach(function(attr) { 136 | styleElement.removeAttribute(attr); 137 | }); 138 | 139 | styleElement.src = blankSrc; 140 | styleElement.srcset = ''; 141 | 142 | styleElementStyle.backgroundRepeat = 'no-repeat'; 143 | styleElementStyle.backgroundPosition = config.position; 144 | styleElementStyle.backgroundSize = config.fit; 145 | 146 | styleElement.setAttribute('data-position', hideElement.style.position); 147 | styleElement.setAttribute('data-visibility', hideElement.style.visibility); 148 | 149 | hideElement.style.visibility = 'hidden'; 150 | hideElement.style.position = 'absolute'; 151 | 152 | element.setAttribute('data-parent-fit', config.fit); 153 | element.setAttribute('data-parent-container', 'prev'); 154 | element.setAttribute('data-object-fit-polyfilled', ''); 155 | element._objectFitPolyfilledDisplay = styleElement; 156 | 157 | container.insertBefore(styleElement, hideElement); 158 | 159 | if(element._lazysizesParentFit){ 160 | delete element._lazysizesParentFit; 161 | } 162 | 163 | if(element.complete){ 164 | onChange(); 165 | } 166 | }); 167 | } 168 | 169 | if(!fitSupport || !positionSupport){ 170 | var onRead = function(e){ 171 | if(e.detail.instance != lazySizes){return;} 172 | 173 | var element = e.target; 174 | var obj = getObject(element); 175 | 176 | if(obj.fit && (!fitSupport || (obj.position != 'center'))){ 177 | initFix(element, obj); 178 | return true; 179 | } 180 | 181 | return false; 182 | }; 183 | 184 | window.addEventListener('lazybeforesizes', function(e) { 185 | if(e.detail.instance != lazySizes){return;} 186 | var element = e.target; 187 | 188 | if (element.getAttribute('data-object-fit-polyfilled') != null && !element._objectFitPolyfilledDisplay) { 189 | if(!onRead(e)){ 190 | lazySizes.rAF(function () { 191 | element.removeAttribute('data-object-fit-polyfilled'); 192 | }); 193 | } 194 | } 195 | }); 196 | window.addEventListener('lazyunveilread', onRead, true); 197 | 198 | if(initialEvent && initialEvent.detail){ 199 | onRead(initialEvent); 200 | } 201 | } 202 | })); 203 | -------------------------------------------------------------------------------- /plugins/object-fit/ls.object-fit.min.js: -------------------------------------------------------------------------------- 1 | /*! lazysizes - v5.3.2 */ 2 | 3 | !function(e,i){var a;e&&(a=function(t){i(e.lazySizes,t),e.removeEventListener("lazyunveilread",a,!0)},i=i.bind(null,e,e.document),"object"==typeof module&&module.exports?i(require("lazysizes")):"function"==typeof define&&define.amd?define(["lazysizes"],i):e.lazySizes?a():e.addEventListener("lazyunveilread",a,!0))}("undefined"!=typeof window?window:0,function(t,u,f,e){"use strict";var y,i,a=u.createElement("a").style,r="objectFit"in a,s=/object-fit["']*\s*:\s*["']*(contain|cover)/,l=/object-position["']*\s*:\s*["']*(.+?)(?=($|,|'|"|;))/,A="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==",n=/\(|\)|'/,d={center:"center","50% 50%":"center"};function c(o,r){function s(){var t=o.currentSrc||o.src;t&&i!==t&&(i=t,d.backgroundImage="url("+(n.test(t)?JSON.stringify(t):t)+")",e||(e=!0,f.rC(l,c.loadingClass),f.aC(l,c.loadedClass)))}function t(){f.rAF(s)}var e,i,l,d,c=f.cfg;o._lazysizesParentFit=r.fit,o.addEventListener("lazyloaded",t,!0),o.addEventListener("load",t,!0),f.rAF(function(){var t,e,i,a=o,n=o.parentNode;"PICTURE"==n.nodeName.toUpperCase()&&(n=(a=n).parentNode),(e=(t=a).previousElementSibling)&&f.hC(e,y)&&(e.parentNode.removeChild(e),t.style.position=e.getAttribute("data-position")||"",t.style.visibility=e.getAttribute("data-visibility")||""),y||y||(i=u.createElement("style"),y=f.cfg.objectFitClass||"lazysizes-display-clone",u.querySelector("head").appendChild(i)),l=o.cloneNode(!1),d=l.style,l.addEventListener("load",function(){var t=l.currentSrc||l.src;t&&t!=A&&(l.src=A,l.srcset="")}),f.rC(l,c.loadedClass),f.rC(l,c.lazyClass),f.rC(l,c.autosizesClass),f.aC(l,c.loadingClass),f.aC(l,y),["data-parent-fit","data-parent-container","data-object-fit-polyfilled",c.srcsetAttr,c.srcAttr].forEach(function(t){l.removeAttribute(t)}),l.src=A,l.srcset="",d.backgroundRepeat="no-repeat",d.backgroundPosition=r.position,d.backgroundSize=r.fit,l.setAttribute("data-position",a.style.position),l.setAttribute("data-visibility",a.style.visibility),a.style.visibility="hidden",a.style.position="absolute",o.setAttribute("data-parent-fit",r.fit),o.setAttribute("data-parent-container","prev"),o.setAttribute("data-object-fit-polyfilled",""),o._objectFitPolyfilledDisplay=l,n.insertBefore(l,a),o._lazysizesParentFit&&delete o._lazysizesParentFit,o.complete&&s()})}r&&(r&&"objectPosition"in a)||(i=function(t){if(t.detail.instance==f){var e,i,a,n=t.target,o=(e=(getComputedStyle(n,null)||{}).fontFamily||"",i=e.match(s)||"",a=(a=i&&e.match(l)||"")&&a[1],{fit:i&&i[1]||"",position:d[a]||a||"center"});return!(!o.fit||r&&"center"==o.position)&&(c(n,o),!0)}},t.addEventListener("lazybeforesizes",function(t){var e;t.detail.instance==f&&(null==(e=t.target).getAttribute("data-object-fit-polyfilled")||e._objectFitPolyfilledDisplay||i(t)||f.rAF(function(){e.removeAttribute("data-object-fit-polyfilled")}))}),t.addEventListener("lazyunveilread",i,!0),e&&e.detail&&i(e))}); -------------------------------------------------------------------------------- /plugins/optimumx/ls.optimumx.min.js: -------------------------------------------------------------------------------- 1 | /*! lazysizes - v5.3.2 */ 2 | 3 | !function(e,t){var n;e&&(n=function(){t(e.lazySizes),e.removeEventListener("lazyunveilread",n,!0)},t=t.bind(null,e,e.document),"object"==typeof module&&module.exports?t(require("lazysizes")):"function"==typeof define&&define.amd?define(["lazysizes"],t):e.lazySizes?n():e.addEventListener("lazyunveilread",n,!0))}("undefined"!=typeof window?window:0,function(t,e,s){"use strict";var c,d,n,r,o,i,l,u,f,m,a;function p(e,t,n,i,r,a,d,u){o.push({c:t,u:n,w:+("w"==u?d:i)})}function v(e,t){return e.w-t.w}function y(e,t){var n={srcset:e.getAttribute(s.cfg.srcsetAttr)||""},i=r(n.srcset);return Object.defineProperty(e,t,{value:n,writable:!0}),n.cands=i,n.index=0,n.dirty=!1,i[0]&&i[0].w?(i.sort(v),n.cSrcset=[i[n.index].c]):(n.cSrcset=n.srcset?[n.srcset]:[],n.cands=[]),n}function g(e,t,n,i,r){var a,d=e[r];d&&(a=d.index,u[r](d,t,n),d.dirty&&a==d.index||(d.cSrcset.join(", "),e.setAttribute(i,d.cSrcset.join(", ")),d.dirty=!0))}t.addEventListener&&(d=/^picture$/i,n=e.documentElement,i=/(([^,\s].[^\s]+)\s+(\d+)(w|h)(\s+(\d+)(w|h))?)/g,r=function(e){return o=[],e.replace(i,p),o},l=function(e,t){var n,i,r,a;if(!e[t]&&(a=e.parentNode||{},e[t]=y(e,t),e[t].isImg=!0,d.test(a.nodeName||"")))for(e[t].picture=!0,i=0,r=(n=a.getElementsByTagName("source")).length;i=c)){if(!(i.d<=n)&&(r=e.cands[c-1],a=i.d,d=n,s=u=void 0,r&&r.d&&(s=.7=d||((u=Math.pow(r.d-s,1.6)||.1)<.1?u=.1:3=devicePixelRatio||(!u||!a._lazyOptimumx||d.reloaded||c.unloadedClass&&s.hC(a,c.unloadedClass)||(a._lazyOptimumx=null),n=l(a,"_lazyOptimumx"),(i=d.width)&&(n.width||0) 21 | 22 | 29 | 30 | 31 | 32 | 38 | 39 | 45 | 46 | 47 | ``` 48 | 49 | 50 | 51 | ### [data-parent-fit="contain|cover|width"] usage 52 | 53 | This plugin also supports calculating height and width constrained images based on a parent element. 54 | 55 | To do so include this plugin, combine your width descriptors with height descriptors and add the attribute ``data-parent-fit`` with either ``"contain"`` or ``"cover"`` as the keyword. 56 | 57 | ```html 58 |
59 | 66 |
67 | ``` 68 | 69 | In case the *width* keyword is used, lazySizes simply takes the width of the parent container instead of the ``img`` element itself. In this case a **h** descriptor isn't necessary. 70 | 71 | ### [data-parent-container="html|.my-image-container"] 72 | Normally the next closest parent that is not a `picture` element is used as the parent (i.e.: `:not(picture)`). This can be changed using the `data-parent-container` option. It takes any simple selector. If you want to use the viewport as the parent simply add `html`. 73 | 74 | As a special keyword the value `self` can be used to signalize, that image itself should be taken. 75 | 76 | ### Controlling `data-parent-fit` and `data-parent-container` with CSS 77 | These option can also be set via CSS by abusing the `font-family` property. 78 | 79 | The `data-parent-fit` option is called here `parent-fit` and `data-parent-container` is called `parent-container`: 80 | 81 | ```css 82 | img.my-image { 83 | font-family: parent-container: html; parent-fit: contain; 84 | } 85 | ``` 86 | 87 | **Note: This plugin should be also added, if you use the [bgset plugin](../bgset/) in combination with ``data-sizes="auto"`` and ``background-size: cover|contain`` and it is also the base of the [object-fit polyfill plugin](../object-fit).** 88 | -------------------------------------------------------------------------------- /plugins/parent-fit/ls.parent-fit.js: -------------------------------------------------------------------------------- 1 | (function(window, factory) { 2 | if(!window) {return;} 3 | var globalInstall = function(){ 4 | factory(window.lazySizes); 5 | window.removeEventListener('lazyunveilread', globalInstall, true); 6 | }; 7 | 8 | factory = factory.bind(null, window, window.document); 9 | 10 | if(typeof module == 'object' && module.exports){ 11 | factory(require('lazysizes')); 12 | } else if (typeof define == 'function' && define.amd) { 13 | define(['lazysizes'], factory); 14 | } else if(window.lazySizes) { 15 | globalInstall(); 16 | } else { 17 | window.addEventListener('lazyunveilread', globalInstall, true); 18 | } 19 | }(typeof window != 'undefined' ? 20 | window : 0, function(window, document, lazySizes) { 21 | 'use strict'; 22 | 23 | if(!window.addEventListener){return;} 24 | 25 | var regDescriptors = /\s+(\d+)(w|h)\s+(\d+)(w|h)/; 26 | var regCssFit = /parent-fit["']*\s*:\s*["']*(contain|cover|width)/; 27 | var regCssObject = /parent-container["']*\s*:\s*["']*(.+?)(?=(\s|$|,|'|"|;))/; 28 | var regPicture = /^picture$/i; 29 | var cfg = lazySizes.cfg; 30 | 31 | var getCSS = function (elem){ 32 | return (getComputedStyle(elem, null) || {}); 33 | }; 34 | 35 | var parentFit = { 36 | 37 | getParent: function(element, parentSel){ 38 | var parent = element; 39 | var parentNode = element.parentNode; 40 | 41 | if((!parentSel || parentSel == 'prev') && parentNode && regPicture.test(parentNode.nodeName || '')){ 42 | parentNode = parentNode.parentNode; 43 | } 44 | 45 | if(parentSel != 'self'){ 46 | if(parentSel == 'prev'){ 47 | parent = element.previousElementSibling; 48 | } else if(parentSel && (parentNode.closest || window.jQuery)){ 49 | parent = (parentNode.closest ? 50 | parentNode.closest(parentSel) : 51 | jQuery(parentNode).closest(parentSel)[0]) || 52 | parentNode 53 | ; 54 | } else { 55 | parent = parentNode; 56 | } 57 | } 58 | 59 | return parent; 60 | }, 61 | 62 | getFit: function(element){ 63 | var tmpMatch, parentObj; 64 | var css = getCSS(element); 65 | var content = css.content || css.fontFamily; 66 | var obj = { 67 | fit: element._lazysizesParentFit || element.getAttribute('data-parent-fit') 68 | }; 69 | 70 | if(!obj.fit && content && (tmpMatch = content.match(regCssFit))){ 71 | obj.fit = tmpMatch[1]; 72 | } 73 | 74 | if(obj.fit){ 75 | parentObj = element._lazysizesParentContainer || element.getAttribute('data-parent-container'); 76 | 77 | if(!parentObj && content && (tmpMatch = content.match(regCssObject))){ 78 | parentObj = tmpMatch[1]; 79 | } 80 | 81 | obj.parent = parentFit.getParent(element, parentObj); 82 | 83 | 84 | } else { 85 | obj.fit = css.objectFit; 86 | } 87 | 88 | return obj; 89 | }, 90 | 91 | getImageRatio: function(element){ 92 | var i, srcset, media, ratio, match, width, height; 93 | var parent = element.parentNode; 94 | var elements = parent && regPicture.test(parent.nodeName || '') ? 95 | parent.querySelectorAll('source, img') : 96 | [element] 97 | ; 98 | 99 | for(i = 0; i < elements.length; i++){ 100 | element = elements[i]; 101 | srcset = element.getAttribute(cfg.srcsetAttr) || element.getAttribute('srcset') || element.getAttribute('data-pfsrcset') || element.getAttribute('data-risrcset') || ''; 102 | media = element._lsMedia || element.getAttribute('media'); 103 | media = cfg.customMedia[element.getAttribute('data-media') || media] || media; 104 | 105 | if(srcset && (!media || (window.matchMedia && matchMedia(media) || {}).matches )){ 106 | ratio = parseFloat(element.getAttribute('data-aspectratio')); 107 | 108 | if (!ratio) { 109 | match = srcset.match(regDescriptors); 110 | 111 | if (match) { 112 | if(match[2] == 'w'){ 113 | width = match[1]; 114 | height = match[3]; 115 | } else { 116 | width = match[3]; 117 | height = match[1]; 118 | } 119 | } else { 120 | width = element.getAttribute('width'); 121 | height = element.getAttribute('height'); 122 | } 123 | 124 | ratio = width / height; 125 | } 126 | 127 | break; 128 | } 129 | } 130 | 131 | return ratio; 132 | }, 133 | 134 | calculateSize: function(element, width){ 135 | var displayRatio, height, imageRatio, retWidth; 136 | var fitObj = this.getFit(element); 137 | var fit = fitObj.fit; 138 | var fitElem = fitObj.parent; 139 | 140 | if(fit != 'width' && ((fit != 'contain' && fit != 'cover') || !(imageRatio = this.getImageRatio(element)))){ 141 | return width; 142 | } 143 | 144 | if(fitElem){ 145 | width = fitElem.clientWidth; 146 | } else { 147 | fitElem = element; 148 | } 149 | 150 | retWidth = width; 151 | 152 | if(fit == 'width'){ 153 | retWidth = width; 154 | } else { 155 | height = fitElem.clientHeight; 156 | 157 | if((displayRatio = width / height) && ((fit == 'cover' && displayRatio < imageRatio) || (fit == 'contain' && displayRatio > imageRatio))){ 158 | retWidth = width * (imageRatio / displayRatio); 159 | } 160 | } 161 | 162 | return retWidth; 163 | } 164 | }; 165 | 166 | lazySizes.parentFit = parentFit; 167 | 168 | document.addEventListener('lazybeforesizes', function(e){ 169 | if(e.defaultPrevented || e.detail.instance != lazySizes){return;} 170 | 171 | var element = e.target; 172 | e.detail.width = parentFit.calculateSize(element, e.detail.width); 173 | }); 174 | })); 175 | -------------------------------------------------------------------------------- /plugins/parent-fit/ls.parent-fit.min.js: -------------------------------------------------------------------------------- 1 | /*! lazysizes - v5.3.2 */ 2 | 3 | !function(t,e){var i;t&&(i=function(){e(t.lazySizes),t.removeEventListener("lazyunveilread",i,!0)},e=e.bind(null,t,t.document),"object"==typeof module&&module.exports?e(require("lazysizes")):"function"==typeof define&&define.amd?define(["lazysizes"],e):t.lazySizes?i():t.addEventListener("lazyunveilread",i,!0))}("undefined"!=typeof window?window:0,function(u,t,i){"use strict";var l,s,d,f,g,o;u.addEventListener&&(l=/\s+(\d+)(w|h)\s+(\d+)(w|h)/,s=/parent-fit["']*\s*:\s*["']*(contain|cover|width)/,d=/parent-container["']*\s*:\s*["']*(.+?)(?=(\s|$|,|'|"|;))/,f=/^picture$/i,g=i.cfg,o={getParent:function(t,e){var i=t,a=t.parentNode;return e&&"prev"!=e||!a||!f.test(a.nodeName||"")||(a=a.parentNode),"self"!=e&&(i="prev"==e?t.previousElementSibling:e&&(a.closest||u.jQuery)&&(a.closest?a.closest(e):jQuery(a).closest(e)[0])||a),i},getFit:function(t){var e,i,a=getComputedStyle(t,null)||{},n=a.content||a.fontFamily,r={fit:t._lazysizesParentFit||t.getAttribute("data-parent-fit")};return!r.fit&&n&&(e=n.match(s))&&(r.fit=e[1]),r.fit?(!(i=t._lazysizesParentContainer||t.getAttribute("data-parent-container"))&&n&&(e=n.match(d))&&(i=e[1]),r.parent=o.getParent(t,i)):r.fit=a.objectFit,r},getImageRatio:function(t){for(var e,i,a,n,r,s,d=t.parentNode,o=d&&f.test(d.nodeName||"")?d.querySelectorAll("source, img"):[t],c=0;c 33 | window.lazySizesConfig = window.lazySizesConfig || {}; 34 | //in case you want to use custom media query aliases in your markup, instead of full media queries 35 | window.lazySizesConfig.customMedia = { 36 | '--small': '(max-width: 480px)', 37 | '--medium': '(max-width: 700px)', 38 | '--large': '(max-width: 1400px)' 39 | }; 40 | 41 | 42 | 43 | 44 | 49 | 50 | 51 | 52 | 53 | 56 | 59 | 62 | 64 | 65 | image with artdirection 69 | 70 | 71 | 72 | 73 | 74 | 78 | 82 | 86 | 89 | 90 | image with artdirection 95 | 96 | 97 | 98 | 103 | ``` 104 | 105 | ### Tip: Using/Generating more complex dynamic ``sizes`` 106 | 107 | As explained above this partial polyfill only accepts one value for ``sizes`` using only the *px* length. Due to the fact, that also ``data-sizes="auto"`` is supported the ``lazybeforesizes`` event can be used to dynamically change/add different ``sizes``: 108 | 109 | ```js 110 | document.addEventListener('lazybeforesizes', function(e){ 111 | //calculate the size as a number 112 | e.detail.width = yourCalculation(e.target) || e.detail.width; 113 | }); 114 | ``` 115 | -------------------------------------------------------------------------------- /plugins/respimg/ls.respimg.min.js: -------------------------------------------------------------------------------- 1 | /*! lazysizes - v5.3.2 */ 2 | 3 | !function(e,t){var r;e&&(r=function(){t(e.lazySizes),e.removeEventListener("lazyunveilread",r,!0)},t=t.bind(null,e,e.document),"object"==typeof module&&module.exports?t(require("lazysizes")):"function"==typeof define&&define.amd?define(["lazysizes"],t):e.lazySizes?r():e.addEventListener("lazyunveilread",r,!0))}("undefined"!=typeof window?window:0,function(d,n,p){"use strict";var i,a,s,l,t,r,f,o,c,m,u,y=p.cfg,e=n.createElement("img"),g="sizes"in e&&"srcset"in e,h=/\s+\d+h/g,z=(a=/\s+(\d+)(w|h)\s+(\d+)(w|h)/,s=Array.prototype.forEach,function(){function r(e){var t,r,i=e.getAttribute(y.srcsetAttr);i&&(r=i.match(a))&&((t="w"==r[2]?r[1]/r[3]:r[3]/r[1])&&e.setAttribute("data-aspectratio",t),e.setAttribute(y.srcsetAttr,i.replace(h,"")))}function e(e){var t;e.detail.instance==p&&((t=e.target.parentNode)&&"PICTURE"==t.nodeName&&s.call(t.getElementsByTagName("source"),r),r(e.target))}function t(){i.currentSrc&&n.removeEventListener("lazybeforeunveil",e)}var i=n.createElement("img");n.addEventListener("lazybeforeunveil",e),i.onload=t,i.onerror=t,i.srcset="data:,a 1w 1h",i.complete&&t()});function v(e,t){return e.w-t.w}function w(e,t,r,i){l.push({c:t,u:r,w:+i})}function b(e,t){var r,i=e.getAttribute("srcset")||e.getAttribute(y.srcsetAttr);!i&&t&&(i=e._lazypolyfill?e._lazypolyfill._set:e.getAttribute(y.srcAttr)||e.getAttribute("src")),e._lazypolyfill&&e._lazypolyfill._set==i||(r=o(i||""),t&&e.parentNode&&(r.isPicture="PICTURE"==e.parentNode.nodeName.toUpperCase(),r.isPicture&&d.matchMedia&&(p.aC(e,"lazymatchmedia"),c())),r._set=i,Object.defineProperty(e,"_lazypolyfill",{value:r,writable:!0}))}function A(e){var t,r,i,n,a,s,l,o,c,u=e;if(b(u,!0),(n=u._lazypolyfill).isPicture)for(r=0,i=(t=e.parentNode.getElementsByTagName("source")).length;r=e.d){!n.cached&&(t=e[a-1])&&t.d>e.d-.13*Math.pow(e.d,2.2)&&(r=Math.pow(t.d-.6,1.6),t.cached&&(t.d+=.15*r),t.d+(n.d-e.d)*r>e.d&&(n=t));break}return n}(n.sort(v)),n.src=a):a=n.src):a=n[0],a}function E(e){var t;g&&e.parentNode&&"PICTURE"!=e.parentNode.nodeName.toUpperCase()||(t=A(e))&&t.u&&e._lazypolyfill.cur!=t.u&&(e._lazypolyfill.cur=t.u,t.cached=!0,e.setAttribute(y.srcAttr,t.u),e.setAttribute("src",t.u))}y.supportsType||(y.supportsType=function(e){return!e}),d.HTMLPictureElement&&g?!p.hasHDescriptorFix&&n.msElementsFromPoint&&(p.hasHDescriptorFix=!0,z()):d.picturefill||y.pf||(y.pf=function(e){var t,r;if(!d.picturefill)for(t=0,r=e.elements.length;t img:not([srcset])."].forEach(function(e){u.push(e+y.loadedClass),u.push(e+y.loadingClass)}),y.pf({elements:n.querySelectorAll(u.join(", "))})))}); -------------------------------------------------------------------------------- /plugins/rias/ls.rias.min.js: -------------------------------------------------------------------------------- 1 | /*! lazysizes - v5.3.2 */ 2 | 3 | !function(t,e){var r=function(){e(t.lazySizes),t.removeEventListener("lazyunveilread",r,!0)};e=e.bind(null,t,t.document),"object"==typeof module&&module.exports?e(require("lazysizes")):"function"==typeof define&&define.amd?define(["lazysizes"],e):t.lazySizes?r():t.addEventListener("lazyunveilread",r,!0)}(window,function(f,u,g){"use strict";var b,m,i=g.cfg,d={string:1,number:1},l=/^\-*\+*\d+\.*\d*$/,p=/^picture$/i,v=/\s*\{\s*width\s*\}\s*/i,y=/\s*\{\s*height\s*\}\s*/i,h=/\s*\{\s*([a-z0-9]+)\s*\}\s*/gi,z=/^\[.*\]|\{.*\}$/,A=/^(?:auto|\d+(px)?)$/,w=u.createElement("a"),t=u.createElement("img"),P="srcset"in t&&!("sizes"in t),E=!!f.HTMLPictureElement&&!P;function N(a,t,s){var e,r,i,n,o,c=f.getComputedStyle(a);if(s){for(n in o={},s)o[n]=s[n];s=o}else r=a.parentNode,s={isPicture:!(!r||!p.test(r.nodeName||""))};for(e in i=function(t,e){var r,i=a.getAttribute("data-"+t);if(i||(r=c.getPropertyValue("--ls-"+t))&&(i=r.trim()),i){if("true"==i)i=!0;else if("false"==i)i=!1;else if(l.test(i))i=parseFloat(i);else if("function"==typeof m[t])i=m[t](a,i);else if(z.test(i))try{i=JSON.parse(i)}catch(t){}s[t]=i}else t in m&&"function"!=typeof m[t]&&!s[t]?s[t]=m[t]:e&&"function"==typeof m[t]&&(s[t]=m[t](a,i))},m)i(e);return t.replace(h,function(t,e){e in s||i(e,!0)}),s}function _(t,e,r){var s,n,o,i=0,a=0,c=r;if(t){if("container"===e.ratio){for(i=c.scrollWidth,a=c.scrollHeight;!(i&&a||c===u);)i=(c=c.parentNode).scrollWidth,a=c.scrollHeight;i&&a&&(e.ratio=e.traditionalRatio?a/i:i/a)}s=t,n=e,(o=[]).srcset=[],n.absUrl&&(w.setAttribute("href",s),s=w.href),s=((n.prefix||"")+s+(n.postfix||"")).replace(h,function(t,e){return d[typeof n[e]]?n[e]:t}),n.widths.forEach(function(t){var e=n.widthmap[t]||t,r=n.aspectratio||n.ratio,i=!n.aspectratio&&m.traditionalRatio,a={u:s.replace(v,e).replace(y,r?i?Math.round(t*r):Math.round(t/r):""),w:t};o.push(a),o.srcset.push(a.c=a.u+" "+t+"w")}),(t=o).isPicture=e.isPicture,P&&"IMG"==r.nodeName.toUpperCase()?r.removeAttribute(b.srcsetAttr):r.setAttribute(b.srcsetAttr,t.srcset.join(", ")),Object.defineProperty(r,"_lazyrias",{value:t,writable:!0})}}function x(t){return t.getAttribute(t.getAttribute("data-srcattr")||m.srcAttr)||t.getAttribute(b.srcsetAttr)||t.getAttribute(b.srcAttr)||t.getAttribute("data-pfsrcset")||""}!function(){var t,e={prefix:"",postfix:"",srcAttr:"data-src",absUrl:!1,modifyOptions:function(){},widthmap:{},ratio:!1,traditionalRatio:!1,aspectratio:!1};for(t in(b=g&&g.cfg).supportsType||(b.supportsType=function(t){return!t}),b.rias||(b.rias={}),"widths"in(m=b.rias)||(m.widths=[],function(t){for(var e,r=0;!e||e<3e3;)30<(r+=5)&&(r+=1),e=36*r,t.push(e)}(m.widths)),e)t in m||(m[t]=e[t])}(),addEventListener("lazybeforesizes",function(t){if(t.detail.instance==g){var e,r,i,a,s,n,o,c,u,d,f,l=t.target;if(t.detail.dataAttr&&!t.defaultPrevented&&!m.disabled&&(o=l.getAttribute(b.sizesAttr)||l.getAttribute("sizes"))&&A.test(o)){var p,y,h=x(l);if(y=N(p=l,h),m.modifyOptions.call(p,{target:p,details:y,detail:y}),g.fire(p,"lazyriasmodifyoptions",y),e=y,u=v.test(e.prefix)||v.test(e.postfix),e.isPicture&&(r=l.parentNode))for(a=0,s=(i=r.getElementsByTagName("source")).length;a=t.d){!a.cached&&(e=t[s-1])&&e.d>t.d-.13*Math.pow(t.d,2.2)&&(r=Math.pow(e.d-.6,1.6),e.cached&&(e.d+=.15*r),e.d+(a.d-t.d)*r>t.d&&(a=e));break}return a}(d.sort(L))),n}}); -------------------------------------------------------------------------------- /plugins/static-gecko-picture/ls.static-gecko-picture.js: -------------------------------------------------------------------------------- 1 | /** 2 | * FF's first picture implementation is static and does not react to viewport changes, this tiny script fixes this. 3 | */ 4 | (function(window, factory) { 5 | var globalInstall = function(){ 6 | factory(window.lazySizes); 7 | window.removeEventListener('lazyunveilread', globalInstall, true); 8 | }; 9 | 10 | factory = factory.bind(null, window, window.document); 11 | 12 | if(typeof module == 'object' && module.exports){ 13 | factory(require('lazysizes')); 14 | } else if (typeof define == 'function' && define.amd) { 15 | define(['lazysizes'], factory); 16 | } else if(window.lazySizes) { 17 | globalInstall(); 18 | } else { 19 | window.addEventListener('lazyunveilread', globalInstall, true); 20 | } 21 | }(window, function(window, document, lazySizes) { 22 | /*jshint eqnull:true */ 23 | var match; 24 | var ua = navigator.userAgent; 25 | 26 | if ( window.HTMLPictureElement && ((/ecko/).test(ua) && (match = ua.match(/rv\:(\d+)/)) && match[1] < 41) ) { 27 | addEventListener("resize", (function() { 28 | var timer; 29 | 30 | var dummySrc = document.createElement("source"); 31 | 32 | var fixRespimg = function(img) { 33 | var source, sizes; 34 | var picture = img.parentNode; 35 | 36 | if (picture.nodeName.toUpperCase() === "PICTURE") { 37 | source = dummySrc.cloneNode(); 38 | 39 | picture.insertBefore(source, picture.firstElementChild); 40 | setTimeout(function() { 41 | picture.removeChild(source); 42 | }); 43 | } else if (!img._pfLastSize || img.offsetWidth > img._pfLastSize) { 44 | img._pfLastSize = img.offsetWidth; 45 | sizes = img.sizes; 46 | img.sizes += ",100vw"; 47 | setTimeout(function() { 48 | img.sizes = sizes; 49 | }); 50 | } 51 | }; 52 | 53 | var findPictureImgs = function() { 54 | var i; 55 | var imgs = document.querySelectorAll("picture > img, img[srcset][sizes]"); 56 | for (i = 0; i < imgs.length; i++) { 57 | fixRespimg(imgs[i]); 58 | } 59 | }; 60 | var onResize = function() { 61 | clearTimeout(timer); 62 | timer = setTimeout(findPictureImgs, 99); 63 | }; 64 | var mq = window.matchMedia && matchMedia("(orientation: landscape)"); 65 | var init = function() { 66 | onResize(); 67 | 68 | if (mq && mq.addListener) { 69 | mq.addListener(onResize); 70 | } 71 | }; 72 | 73 | dummySrc.srcset = "data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw=="; 74 | 75 | if (/^[c|i]|d$/.test(document.readyState || "")) { 76 | init(); 77 | } else { 78 | document.addEventListener("DOMContentLoaded", init); 79 | } 80 | 81 | return onResize; 82 | })()); 83 | } 84 | })); 85 | -------------------------------------------------------------------------------- /plugins/static-gecko-picture/ls.static-gecko-picture.min.js: -------------------------------------------------------------------------------- 1 | /*! lazysizes - v5.3.2 */ 2 | 3 | !function(e,t){var i=function(){t(e.lazySizes),e.removeEventListener("lazyunveilread",i,!0)};t=t.bind(null,e,e.document),"object"==typeof module&&module.exports?t(require("lazysizes")):"function"==typeof define&&define.amd?define(["lazysizes"],t):e.lazySizes?i():e.addEventListener("lazyunveilread",i,!0)}(window,function(e,i,t){var n,a,s,o,r=navigator.userAgent;function d(){for(var e=i.querySelectorAll("picture > img, img[srcset][sizes]"),t=0;te._pfLastSize)&&(e._pfLastSize=e.offsetWidth,i=e.sizes,e.sizes+=",100vw",setTimeout(function(){e.sizes=i}))}(e[t])}function c(){clearTimeout(a),a=setTimeout(d,99)}function f(){c(),o&&o.addListener&&o.addListener(c)}e.HTMLPictureElement&&/ecko/.test(r)&&(n=r.match(/rv\:(\d+)/))&&n[1]<41&&addEventListener("resize",(s=i.createElement("source"),o=e.matchMedia&&matchMedia("(orientation: landscape)"),s.srcset="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==",/^[c|i]|d$/.test(i.readyState||"")?f():i.addEventListener("DOMContentLoaded",f),c))}); -------------------------------------------------------------------------------- /plugins/twitter/ls.twitter.js: -------------------------------------------------------------------------------- 1 | (function(window, factory) { 2 | if(!window) {return;} 3 | var globalInstall = function(){ 4 | factory(window.lazySizes); 5 | window.removeEventListener('lazyunveilread', globalInstall, true); 6 | }; 7 | 8 | factory = factory.bind(null, window, window.document); 9 | 10 | if(typeof module == 'object' && module.exports){ 11 | factory(require('lazysizes')); 12 | } else if (typeof define == 'function' && define.amd) { 13 | define(['lazysizes'], factory); 14 | } else if(window.lazySizes) { 15 | globalInstall(); 16 | } else { 17 | window.addEventListener('lazyunveilread', globalInstall, true); 18 | } 19 | }(typeof window != 'undefined' ? 20 | window : 0, function(window, document, lazySizes) { 21 | /* 22 | @example 23 |

Nothing Twitter is doing is working https://t.co/s0FppnacwK pic.twitter.com/GK9MRfQkYO

— The Verge (@verge) April 26, 2016
24 | 25 | 31 | Tweets by @TwitterDev 32 | 33 | */ 34 | 'use strict'; 35 | var scriptadded; 36 | 37 | function loadExecuteTwitter(){ 38 | if(window.twttr && twttr.widgets){ 39 | twttr.widgets.load(); 40 | return; 41 | } 42 | 43 | if(scriptadded){ 44 | return; 45 | } 46 | 47 | var elem = document.createElement('script'); 48 | var insertElem = document.getElementsByTagName('script')[0]; 49 | 50 | elem.src = '//platform.twitter.com/widgets.js'; 51 | 52 | scriptadded = true; 53 | insertElem.parentNode.insertBefore(elem, insertElem); 54 | } 55 | 56 | document.addEventListener('lazybeforeunveil', function(e){ 57 | if(e.detail.instance != lazySizes){return;} 58 | 59 | var twttrWidget = e.target.getAttribute('data-twitter'); 60 | 61 | if(twttrWidget){ 62 | lazySizes.aC(e.target, twttrWidget); 63 | loadExecuteTwitter(); 64 | } 65 | }); 66 | 67 | })); 68 | -------------------------------------------------------------------------------- /plugins/twitter/ls.twitter.min.js: -------------------------------------------------------------------------------- 1 | /*! lazysizes - v5.3.2 */ 2 | 3 | !function(e,t){var i;e&&(i=function(){t(e.lazySizes),e.removeEventListener("lazyunveilread",i,!0)},t=t.bind(null,e,e.document),"object"==typeof module&&module.exports?t(require("lazysizes")):"function"==typeof define&&define.amd?define(["lazysizes"],t):e.lazySizes?i():e.addEventListener("lazyunveilread",i,!0))}("undefined"!=typeof window?window:0,function(r,a,d){"use strict";var o;a.addEventListener("lazybeforeunveil",function(e){var t,i,n;e.detail.instance!=d||(t=e.target.getAttribute("data-twitter"))&&(d.aC(e.target,t),r.twttr&&twttr.widgets?twttr.widgets.load():o||(i=a.createElement("script"),n=a.getElementsByTagName("script")[0],i.src="//platform.twitter.com/widgets.js",o=!0,n.parentNode.insertBefore(i,n)))})}); -------------------------------------------------------------------------------- /plugins/unload/README.md: -------------------------------------------------------------------------------- 1 | # lazysizes unload 2 | 3 | Unloads ``img.lazyload`` (including ``picture``) elements if they consume a lot of memory and they are out of view. To improve memory consumption as also resize/orientationchange performance. 4 | 5 | ## Usage 6 | 7 | Simply add the lazysizes unload extension to your site. 8 | 9 | ## Options 10 | 11 | * ``lazySizesConfig.unloadClass`` (default: ``"lazyunload"``): Elements with this class will be unloaded even if they only consume less memory/pixels than defined in ``unloadPixelThreshold``. 12 | * ``lazySizesConfig.unloadedClass`` (default: ``"lazyunloaded"``): If an element was unloaded it becomes the class ``lazyunloaded``. 13 | * ``lazySizesConfig.unloadPixelThreshold`` (default: Number is dynamically calculated): If the amount of image pixels exceeds this threshold this image will be unloaded. 14 | * ``lazySizesConfig.autoUnload`` (default: ``true``): Whether unloading should happen automatically with all lazyload images. If set to false, only elements with the class ``lazyunload`` will be unloaded. 15 | * ``lazySizesConfig.emptySrc`` (default: transparent data uri): The src to be used as unload image. 16 | * ``lazySizesConfig.unloadHidden`` (default: ``true``): Whether hidden images (``display: none;``) also should be unloaded. 17 | 18 | **Note**: In case you dynamically change the ``data-src``/``data-srcset`` of an already unloaded element, you have to remove the ``lazyunloaded`` class. 19 | 20 | ## Events 21 | 22 | * ``lazyafterunload``: This event will be fired on the unloaded lazyload elements. This event can be used to extend the unload functionality. 23 | ```js 24 | //div ajax example which returns DOM string: 25 | document.addEventListener('lazybeforeunveil', function (e) { 26 | var containerId = e.target.getAttribute('data-id'); 27 | 28 | //load ajax content with containerId 29 | //append content to e.target.innerHTML 30 | }); 31 | 32 | //clean DOM nodes inside container that where previously loaded by ajax: 33 | //lazyafterunload gives possibility to take care of the cleanup in this case 34 | document.addEventListener('lazyafterunload', function (e) { 35 | var container = e.target; 36 | 37 | while (container.firstElementChild) { 38 | container.removeChild(container.firstElementChild); 39 | } 40 | }); 41 | ``` 42 | -------------------------------------------------------------------------------- /plugins/unload/ls.unload.js: -------------------------------------------------------------------------------- 1 | (function(window, factory) { 2 | var globalInstall = function(){ 3 | factory(window.lazySizes); 4 | window.removeEventListener('lazyunveilread', globalInstall, true); 5 | }; 6 | 7 | factory = factory.bind(null, window, window.document); 8 | 9 | if(typeof module == 'object' && module.exports){ 10 | factory(require('lazysizes')); 11 | } else if (typeof define == 'function' && define.amd) { 12 | define(['lazysizes'], factory); 13 | } else if(window.lazySizes) { 14 | globalInstall(); 15 | } else { 16 | window.addEventListener('lazyunveilread', globalInstall, true); 17 | } 18 | }(window, function(window, document, lazySizes) { 19 | 'use strict'; 20 | if(!document.addEventListener){return;} 21 | var config, checkElements; 22 | 23 | var lazySizesCfg = lazySizes.cfg; 24 | var unloadElements = []; 25 | var requestAnimationFrame = window.requestAnimationFrame || setTimeout; 26 | var unloader = { 27 | checkElements: function(){ 28 | var i, len, box; 29 | 30 | var expand = (lazySizes._defEx + 99) * 1.1; 31 | var vTop = expand * -1; 32 | var vLeft = vTop; 33 | var vBottom = innerHeight + expand; 34 | var vRight = innerWidth + expand; 35 | 36 | for(i = 0, len = checkElements.length; i < len; i++){ 37 | box = checkElements[i].getBoundingClientRect(); 38 | 39 | if((box.top > vBottom || box.bottom < vTop || box.left > vRight || box.right < vLeft) || 40 | (config.unloadHidden && !box.top && !box.bottom && !box.left && !box.right)){ 41 | unloadElements.push(checkElements[i]); 42 | } 43 | } 44 | requestAnimationFrame(unloader.unloadElements); 45 | }, 46 | unload: function(element){ 47 | var sources, isResponsive, i, len; 48 | var picture = element.parentNode; 49 | lazySizes.rC(element, config.loadedClass); 50 | 51 | if(element.getAttribute(config.srcsetAttr)){ 52 | element.setAttribute('srcset', config.emptySrc); 53 | isResponsive = true; 54 | } 55 | 56 | if(picture && picture.nodeName.toUpperCase() == 'PICTURE'){ 57 | sources = picture.getElementsByTagName('source'); 58 | 59 | for(i = 0, len = sources.length; i < len; i++){ 60 | sources[i].setAttribute('srcset', config.emptySrc); 61 | } 62 | 63 | isResponsive = true; 64 | } 65 | 66 | if(lazySizes.hC(element, config.autosizesClass)){ 67 | lazySizes.rC(element, config.autosizesClass); 68 | element.setAttribute(config.sizesAttr, 'auto'); 69 | } 70 | 71 | if(isResponsive || element.getAttribute(config.srcAttr)){ 72 | element.src = config.emptySrc; 73 | } 74 | 75 | lazySizes.aC(element, config.unloadedClass); 76 | lazySizes.aC(element, config.lazyClass); 77 | lazySizes.fire(element, 'lazyafterunload'); 78 | }, 79 | unloadElements: function(elements){ 80 | elements = Array.isArray(elements) ? elements : unloadElements; 81 | 82 | while(elements.length){ 83 | unloader.unload(elements.shift()); 84 | } 85 | }, 86 | _reload: function(e) { 87 | if(lazySizes.hC(e.target, config.unloadedClass) && e.detail){ 88 | e.detail.reloaded = true; 89 | lazySizes.rC(e.target, config.unloadedClass); 90 | } 91 | } 92 | }; 93 | 94 | function init(){ 95 | if(!window.lazySizes || checkElements){return;} 96 | var docElem = document.documentElement; 97 | var throttleRun = (function(){ 98 | var running; 99 | var run = function(){ 100 | unloader.checkElements(); 101 | running = false; 102 | }; 103 | return function(){ 104 | if(!running){ 105 | running = true; 106 | setTimeout(run, 999); 107 | } 108 | }; 109 | })(); 110 | 111 | config = lazySizes.cfg; 112 | removeEventListener('lazybeforeunveil', init); 113 | 114 | if(!('unloadClass' in config)){ 115 | config.unloadClass = 'lazyunload'; 116 | } 117 | 118 | if(!('unloadedClass' in config)){ 119 | config.unloadedClass = 'lazyunloaded'; 120 | } 121 | 122 | if(!('unloadHidden' in config)){ 123 | config.unloadHidden = true; 124 | } 125 | 126 | if(!('emptySrc' in config)){ 127 | config.emptySrc = 'data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw=='; 128 | } 129 | 130 | if(!('autoUnload' in config)){ 131 | config.autoUnload = true; 132 | } 133 | 134 | if(!('unloadPixelThreshold' in config)){ 135 | config.unloadPixelThreshold = 60000; 136 | } 137 | 138 | if(config.autoUnload){ 139 | docElem.addEventListener('load', function(e){ 140 | if(e.target.naturalWidth * e.target.naturalHeight > config.unloadPixelThreshold && e.target.className && 141 | e.target.className.indexOf && e.target.className.indexOf(lazySizesCfg.loadingClass) != -1 && 142 | e.target.className.indexOf(lazySizesCfg.preloadClass) == -1){ 143 | lazySizes.aC(e.target, lazySizesCfg.unloadClass); 144 | } 145 | }, true); 146 | } 147 | 148 | lazySizes.unloader = unloader; 149 | 150 | checkElements = document.getElementsByClassName([config.unloadClass, config.loadedClass].join(' ')); 151 | 152 | setInterval(throttleRun, 9999); 153 | addEventListener('lazybeforeunveil', throttleRun); 154 | addEventListener('lazybeforeunveil', unloader._reload, true); 155 | } 156 | 157 | addEventListener('lazybeforeunveil', init); 158 | })); 159 | -------------------------------------------------------------------------------- /plugins/unload/ls.unload.min.js: -------------------------------------------------------------------------------- 1 | /*! lazysizes - v5.3.2 */ 2 | 3 | !function(e,t){var a=function(){t(e.lazySizes),e.removeEventListener("lazyunveilread",a,!0)};t=t.bind(null,e,e.document),"object"==typeof module&&module.exports?t(require("lazysizes")):"function"==typeof define&&define.amd?define(["lazysizes"],t):e.lazySizes?a():e.addEventListener("lazyunveilread",a,!0)}(window,function(s,d,i){"use strict";var r,u,o,c,f,A;d.addEventListener&&(o=i.cfg,c=[],f=s.requestAnimationFrame||setTimeout,A={checkElements:function(){for(var e,t=1.1*(i._defEx+99),a=-1*t,n=a,l=innerHeight+t,s=innerWidth+t,d=0,o=u.length;dl||e.bottoms||e.rightr.unloadPixelThreshold&&e.target.className&&e.target.className.indexOf&&-1!=e.target.className.indexOf(o.loadingClass)&&-1==e.target.className.indexOf(o.preloadClass)&&i.aC(e.target,o.unloadClass)},!0),i.unloader=A,u=d.getElementsByClassName([r.unloadClass,r.loadedClass].join(" ")),setInterval(a,9999),addEventListener("lazybeforeunveil",a),addEventListener("lazybeforeunveil",A._reload,!0))}))}); -------------------------------------------------------------------------------- /plugins/unveilhooks/README.md: -------------------------------------------------------------------------------- 1 | # lazysizes unveilhooks extension 2 | 3 | The unveilhooks plugin extends lazySizes to also unveil / lazyload scripts/widgets, background images, styles and video/audio elements: 4 | 5 | ```html 6 | 7 |
8 | 9 |
10 | 11 | 12 |
13 | 14 |
15 | 16 | 17 |
18 | 19 |
20 | 21 | 22 | 25 | 26 | 27 |
28 | 29 | 30 | 31 |
32 | 33 |
34 | ``` 35 | 36 | Note: In case you want to lazyload a background image via a ``class`` you can do so by using the ``addClasses`` option: 37 | 38 | ```html 39 | 44 | 45 |
46 | 47 |
48 | ``` 49 | 50 | For support responsive background images see the [bgset extension](../bgset). 51 | 52 | For more complex loading of styles and AMD modules please see the [include extension](../include). 53 | 54 | Note: To support the require example you need to the requireJs option: 55 | 56 | ```js 57 | window.lazySizesConfig = window.lazySizesConfig || {}; 58 | window.lazySizesConfig.requireJs = function(modules, cb){ 59 | window.require(modules, cb); 60 | }; 61 | ``` 62 | 63 | 64 | -------------------------------------------------------------------------------- /plugins/unveilhooks/ls.unveilhooks.js: -------------------------------------------------------------------------------- 1 | /* 2 | This plugin extends lazySizes to lazyLoad: 3 | background images, videos/posters and scripts 4 | 5 | Background-Image: 6 | For background images, use data-bg attribute: 7 |
8 | 9 | Video: 10 | For video/audio use data-poster and preload="none": 11 | 14 | 15 | For video that plays automatically if in view: 16 | 24 | 25 | Scripts: 26 | For scripts use data-script: 27 |
28 | 29 | 30 | Script modules using require: 31 | For modules using require use data-require: 32 |
33 | */ 34 | 35 | (function(window, factory) { 36 | var globalInstall = function(){ 37 | factory(window.lazySizes); 38 | window.removeEventListener('lazyunveilread', globalInstall, true); 39 | }; 40 | 41 | factory = factory.bind(null, window, window.document); 42 | 43 | if(typeof module == 'object' && module.exports){ 44 | factory(require('lazysizes')); 45 | } else if (typeof define == 'function' && define.amd) { 46 | define(['lazysizes'], factory); 47 | } else if(window.lazySizes) { 48 | globalInstall(); 49 | } else { 50 | window.addEventListener('lazyunveilread', globalInstall, true); 51 | } 52 | }(window, function(window, document, lazySizes) { 53 | /*jshint eqnull:true */ 54 | 'use strict'; 55 | var bgLoad, regBgUrlEscape; 56 | var uniqueUrls = {}; 57 | 58 | if(document.addEventListener){ 59 | regBgUrlEscape = /\(|\)|\s|'/; 60 | 61 | bgLoad = function (url, cb){ 62 | var img = document.createElement('img'); 63 | img.onload = function(){ 64 | img.onload = null; 65 | img.onerror = null; 66 | img = null; 67 | cb(); 68 | }; 69 | img.onerror = img.onload; 70 | 71 | img.src = url; 72 | 73 | if(img && img.complete && img.onload){ 74 | img.onload(); 75 | } 76 | }; 77 | 78 | addEventListener('lazybeforeunveil', function(e){ 79 | if(e.detail.instance != lazySizes){return;} 80 | 81 | var tmp, load, bg, poster; 82 | if(!e.defaultPrevented) { 83 | 84 | var target = e.target; 85 | 86 | if(target.preload == 'none'){ 87 | target.preload = target.getAttribute('data-preload') || 'auto'; 88 | } 89 | 90 | if (target.getAttribute('data-autoplay') != null) { 91 | if (target.getAttribute('data-expand') && !target.autoplay) { 92 | try { 93 | target.play(); 94 | } catch (er) {} 95 | } else { 96 | requestAnimationFrame(function () { 97 | target.setAttribute('data-expand', '-10'); 98 | lazySizes.aC(target, lazySizes.cfg.lazyClass); 99 | }); 100 | } 101 | } 102 | 103 | tmp = target.getAttribute('data-link'); 104 | if(tmp){ 105 | addStyleScript(tmp, true); 106 | } 107 | 108 | // handle data-script 109 | tmp = target.getAttribute('data-script'); 110 | if(tmp){ 111 | e.detail.firesLoad = true; 112 | load = function(){ 113 | e.detail.firesLoad = false; 114 | lazySizes.fire(target, '_lazyloaded', {}, true, true); 115 | }; 116 | addStyleScript(tmp, null, load); 117 | } 118 | 119 | // handle data-require 120 | tmp = target.getAttribute('data-require'); 121 | if(tmp){ 122 | if(lazySizes.cfg.requireJs){ 123 | lazySizes.cfg.requireJs([tmp]); 124 | } else { 125 | addStyleScript(tmp); 126 | } 127 | } 128 | 129 | // handle data-bg 130 | bg = target.getAttribute('data-bg'); 131 | if (bg) { 132 | e.detail.firesLoad = true; 133 | load = function(){ 134 | target.style.backgroundImage = 'url(' + (regBgUrlEscape.test(bg) ? JSON.stringify(bg) : bg ) + ')'; 135 | e.detail.firesLoad = false; 136 | lazySizes.fire(target, '_lazyloaded', {}, true, true); 137 | }; 138 | 139 | bgLoad(bg, load); 140 | } 141 | 142 | // handle data-poster 143 | poster = target.getAttribute('data-poster'); 144 | if(poster){ 145 | e.detail.firesLoad = true; 146 | load = function(){ 147 | target.poster = poster; 148 | e.detail.firesLoad = false; 149 | lazySizes.fire(target, '_lazyloaded', {}, true, true); 150 | }; 151 | 152 | bgLoad(poster, load); 153 | 154 | } 155 | } 156 | }, false); 157 | 158 | } 159 | 160 | function addStyleScript(src, style, cb){ 161 | if(uniqueUrls[src]){ 162 | return; 163 | } 164 | var elem = document.createElement(style ? 'link' : 'script'); 165 | var insertElem = document.getElementsByTagName('script')[0]; 166 | 167 | if(style){ 168 | elem.rel = 'stylesheet'; 169 | elem.href = src; 170 | } else { 171 | elem.onload = function(){ 172 | elem.onerror = null; 173 | elem.onload = null; 174 | cb(); 175 | }; 176 | elem.onerror = elem.onload; 177 | 178 | elem.src = src; 179 | } 180 | uniqueUrls[src] = true; 181 | uniqueUrls[elem.src || elem.href] = true; 182 | insertElem.parentNode.insertBefore(elem, insertElem); 183 | } 184 | })); 185 | -------------------------------------------------------------------------------- /plugins/unveilhooks/ls.unveilhooks.min.js: -------------------------------------------------------------------------------- 1 | /*! lazysizes - v5.3.2 */ 2 | 3 | !function(e,t){var a=function(){t(e.lazySizes),e.removeEventListener("lazyunveilread",a,!0)};t=t.bind(null,e,e.document),"object"==typeof module&&module.exports?t(require("lazysizes")):"function"==typeof define&&define.amd?define(["lazysizes"],t):e.lazySizes?a():e.addEventListener("lazyunveilread",a,!0)}(window,function(e,i,o){"use strict";var l,d,u={};function s(e,t,a){var n,r;u[e]||(n=i.createElement(t?"link":"script"),r=i.getElementsByTagName("script")[0],t?(n.rel="stylesheet",n.href=e):(n.onload=function(){n.onerror=null,n.onload=null,a()},n.onerror=n.onload,n.src=e),u[e]=!0,u[n.src||n.href]=!0,r.parentNode.insertBefore(n,r))}i.addEventListener&&(l=function(e,t){var a=i.createElement("img");a.onload=function(){a.onload=null,a.onerror=null,a=null,t()},a.onerror=a.onload,a.src=e,a&&a.complete&&a.onload&&a.onload()},addEventListener("lazybeforeunveil",function(e){var t,a,n;if(e.detail.instance==o&&!e.defaultPrevented){var r=e.target;if("none"==r.preload&&(r.preload=r.getAttribute("data-preload")||"auto"),null!=r.getAttribute("data-autoplay"))if(r.getAttribute("data-expand")&&!r.autoplay)try{r.play()}catch(e){}else requestAnimationFrame(function(){r.setAttribute("data-expand","-10"),o.aC(r,o.cfg.lazyClass)});(t=r.getAttribute("data-link"))&&s(t,!0),(t=r.getAttribute("data-script"))&&(e.detail.firesLoad=!0,s(t,null,function(){e.detail.firesLoad=!1,o.fire(r,"_lazyloaded",{},!0,!0)})),(t=r.getAttribute("data-require"))&&(o.cfg.requireJs?o.cfg.requireJs([t]):s(t)),(a=r.getAttribute("data-bg"))&&(e.detail.firesLoad=!0,l(a,function(){r.style.backgroundImage="url("+(d.test(a)?JSON.stringify(a):a)+")",e.detail.firesLoad=!1,o.fire(r,"_lazyloaded",{},!0,!0)})),(n=r.getAttribute("data-poster"))&&(e.detail.firesLoad=!0,l(n,function(){r.poster=n,e.detail.firesLoad=!1,o.fire(r,"_lazyloaded",{},!0,!0)}))}},!(d=/\(|\)|\s|'/)))}); -------------------------------------------------------------------------------- /plugins/video-embed/README.md: -------------------------------------------------------------------------------- 1 | TBD 2 | 3 | ```html 4 |
5 | 6 |
7 | 8 |
9 | 10 |
11 | ``` 12 | -------------------------------------------------------------------------------- /plugins/video-embed/ls.video-embed.js: -------------------------------------------------------------------------------- 1 | (function(window, factory) { 2 | if(!window) {return;} 3 | var globalInstall = function(){ 4 | factory(window.lazySizes); 5 | window.removeEventListener('lazyunveilread', globalInstall, true); 6 | }; 7 | 8 | factory = factory.bind(null, window, window.document); 9 | 10 | if(typeof module == 'object' && module.exports){ 11 | factory(require('lazysizes')); 12 | } else if (typeof define == 'function' && define.amd) { 13 | define(['lazysizes'], factory); 14 | } else if(window.lazySizes) { 15 | globalInstall(); 16 | } else { 17 | window.addEventListener('lazyunveilread', globalInstall, true); 18 | } 19 | }(typeof window != 'undefined' ? 20 | window : 0, function(window, document, lazySizes) { 21 | /*jshint eqnull:true */ 22 | 'use strict'; 23 | if(!document.getElementsByClassName){return;} 24 | var protocol = location.protocol == 'https:' ? 25 | 'https:' : 26 | 'http:' 27 | ; 28 | var idIndex = Date.now(); 29 | var regId = /\{\{id}}/; 30 | var regYtImg = /\{\{hqdefault}}/; 31 | var regAmp = /^&/; 32 | var regValidParam = /^[a-z0-9-_&=]+$/i; 33 | var youtubeImg = protocol + '//img.youtube.com/vi/{{id}}/{{hqdefault}}.jpg'; 34 | var youtubeIframe = protocol + '//www.youtube.com/embed/{{id}}?autoplay=1'; 35 | var vimeoApi = protocol + '//vimeo.com/api/oembed.json?url=https%3A//vimeo.com/{{id}}'; 36 | var vimeoIframe = protocol + '//player.vimeo.com/video/{{id}}?autoplay=1'; 37 | 38 | function getJSON(url, callback){ 39 | var id = 'vimeoCallback' + idIndex; 40 | var script = document.createElement('script'); 41 | url += '&callback='+id; 42 | 43 | idIndex++; 44 | 45 | window[id] = function(data){ 46 | script.parentNode.removeChild(script); 47 | delete window[id]; 48 | callback(data); 49 | }; 50 | 51 | script.src = url; 52 | 53 | document.head.appendChild(script); 54 | } 55 | 56 | function embedVimeoImg(id, elem){ 57 | getJSON(vimeoApi.replace(regId, id), function(data){ 58 | if(data && data.thumbnail_url){ 59 | elem.style.backgroundImage = 'url('+ data.thumbnail_url +')'; 60 | } 61 | }); 62 | elem.addEventListener('click', embedVimeoIframe); 63 | } 64 | 65 | function embedVimeoIframe(e){ 66 | var elem = e.currentTarget; 67 | var id = elem.getAttribute('data-vimeo'); 68 | var vimeoParams = elem.getAttribute('data-vimeoparams') || ''; 69 | 70 | elem.removeEventListener('click', embedVimeoIframe); 71 | 72 | if (!id || !regValidParam.test(id) || (vimeoParams && !regValidParam.test(vimeoParams))) { 73 | return; 74 | } 75 | 76 | if(vimeoParams && !regAmp.test(vimeoParams)){ 77 | vimeoParams = '&'+ vimeoParams; 78 | } 79 | 80 | e.preventDefault(); 81 | 82 | elem.innerHTML = '' 84 | ; 85 | 86 | } 87 | 88 | function embedYoutubeImg(id, elem){ 89 | var ytImg = elem.getAttribute('data-thumb-size') || lazySizes.cfg.ytThumb || 'hqdefault'; 90 | 91 | elem.style.backgroundImage = 'url('+ youtubeImg.replace(regId, id).replace(regYtImg, ytImg) +')'; 92 | elem.addEventListener('click', embedYoutubeIframe); 93 | } 94 | 95 | function embedYoutubeIframe(e){ 96 | var elem = e.currentTarget; 97 | var id = elem.getAttribute('data-youtube'); 98 | var youtubeParams = elem.getAttribute('data-ytparams') || ''; 99 | 100 | elem.removeEventListener('click', embedYoutubeIframe); 101 | 102 | if (!id || !regValidParam.test(id) || (youtubeParams && !regValidParam.test(youtubeParams))) { 103 | return; 104 | } 105 | 106 | if(youtubeParams && !regAmp.test(youtubeParams)){ 107 | youtubeParams = '&'+ youtubeParams; 108 | } 109 | 110 | e.preventDefault(); 111 | 112 | elem.innerHTML = '' 114 | ; 115 | } 116 | 117 | document.addEventListener('lazybeforeunveil', function(e){ 118 | if(e.detail.instance != lazySizes){return;} 119 | 120 | var elem = e.target; 121 | var youtube = elem.getAttribute('data-youtube'); 122 | var vimeo = elem.getAttribute('data-vimeo'); 123 | 124 | if(youtube && elem){ 125 | embedYoutubeImg(youtube, elem); 126 | } 127 | if(vimeo && elem){ 128 | embedVimeoImg(vimeo, elem); 129 | } 130 | }); 131 | })); 132 | -------------------------------------------------------------------------------- /plugins/video-embed/ls.video-embed.min.js: -------------------------------------------------------------------------------- 1 | /*! lazysizes - v5.3.2 */ 2 | 3 | !function(e,t){var a;e&&(a=function(){t(e.lazySizes),e.removeEventListener("lazyunveilread",a,!0)},t=t.bind(null,e,e.document),"object"==typeof module&&module.exports?t(require("lazysizes")):"function"==typeof define&&define.amd?define(["lazysizes"],t):e.lazySizes?a():e.addEventListener("lazyunveilread",a,!0))}("undefined"!=typeof window?window:0,function(l,o,u){"use strict";var e,d,c,s,r,n,m,f,v,p;function b(e,t){var a,i,r,n;a=v.replace(c,e),i=function(e){e&&e.thumbnail_url&&(t.style.backgroundImage="url("+e.thumbnail_url+")")},r="vimeoCallback"+d,n=o.createElement("script"),a+="&callback="+r,d++,l[r]=function(e){n.parentNode.removeChild(n),delete l[r],i(e)},n.src=a,o.head.appendChild(n),t.addEventListener("click",y)}function y(e){var t=e.currentTarget,a=t.getAttribute("data-vimeo"),i=t.getAttribute("data-vimeoparams")||"";t.removeEventListener("click",y),a&&n.test(a)&&(!i||n.test(i))&&(i&&!r.test(i)&&(i="&"+i),e.preventDefault(),t.innerHTML='')}function g(e){var t=e.currentTarget,a=t.getAttribute("data-youtube"),i=t.getAttribute("data-ytparams")||"";t.removeEventListener("click",g),a&&n.test(a)&&(!i||n.test(i))&&(i&&!r.test(i)&&(i="&"+i),e.preventDefault(),t.innerHTML='')}o.getElementsByClassName&&(e="https:"==location.protocol?"https:":"http:",d=Date.now(),c=/\{\{id}}/,s=/\{\{hqdefault}}/,r=/^&/,n=/^[a-z0-9-_&=]+$/i,m=e+"//img.youtube.com/vi/{{id}}/{{hqdefault}}.jpg",f=e+"//www.youtube.com/embed/{{id}}?autoplay=1",v=e+"//vimeo.com/api/oembed.json?url=https%3A//vimeo.com/{{id}}",p=e+"//player.vimeo.com/video/{{id}}?autoplay=1",o.addEventListener("lazybeforeunveil",function(e){var t,a,i,r,n,l;e.detail.instance==u&&(a=(t=e.target).getAttribute("data-youtube"),i=t.getAttribute("data-vimeo"),a&&t&&(r=a,l=(n=t).getAttribute("data-thumb-size")||u.cfg.ytThumb||"hqdefault",n.style.backgroundImage="url("+m.replace(c,r).replace(s,l)+")",n.addEventListener("click",g)),i&&t&&b(i,t))}))}); -------------------------------------------------------------------------------- /src/common.wrapper: -------------------------------------------------------------------------------- 1 | (function(window, factory) { 2 | var lazySizes = factory(window, window.document, Date); 3 | window.lazySizes = lazySizes; 4 | if(typeof module == 'object' && module.exports){ 5 | module.exports = lazySizes; 6 | } 7 | }(typeof window != 'undefined' ? 8 | window : {}, {{ls}})); 9 | -------------------------------------------------------------------------------- /src/umd.wrapper: -------------------------------------------------------------------------------- 1 | (function(window, factory) { 2 | var lazySizes = factory(window, window.document, Date); 3 | if(typeof module == 'object' && module.exports){ 4 | module.exports = lazySizes; 5 | } else if (typeof define == 'function' && define.amd) { 6 | define(lazySizes); 7 | } else { 8 | window.lazySizes = lazySizes; 9 | } 10 | }(window, {{ls}})); 11 | -------------------------------------------------------------------------------- /tests/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 31 | 32 | 33 |
34 |
35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /tests/test-files/content-file.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 19 | 25 | 26 | 27 | 58 | 59 | 60 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | -------------------------------------------------------------------------------- /tests/test-files/matchMedia.js: -------------------------------------------------------------------------------- 1 | /*! matchMedia() polyfill - Test a CSS media type/query in JS. Authors & copyright (c) 2012: Scott Jehl, Paul Irish, Nicholas Zakas, David Knight. Dual MIT/BSD license */ 2 | 3 | window.matchMedia || (window.matchMedia = function() { 4 | "use strict"; 5 | 6 | // For browsers that support matchMedium api such as IE 9 and webkit 7 | var styleMedia = (window.styleMedia || window.media); 8 | 9 | // For those that don't support matchMedium 10 | if (!styleMedia) { 11 | var style = document.createElement('style'), 12 | script = document.getElementsByTagName('script')[0], 13 | info = null; 14 | 15 | style.type = 'text/css'; 16 | style.id = 'matchmediajs-test'; 17 | 18 | script.parentNode.insertBefore(style, script); 19 | 20 | // 'style.currentStyle' is used by IE <= 8 and 'window.getComputedStyle' for all other browsers 21 | info = ('getComputedStyle' in window) && window.getComputedStyle(style, null) || style.currentStyle; 22 | 23 | styleMedia = { 24 | matchMedium: function(media) { 25 | var text = '@media ' + media + '{ #matchmediajs-test { width: 1px; } }'; 26 | 27 | // 'style.styleSheet' is used by IE <= 8 and 'style.textContent' for all other browsers 28 | if (style.styleSheet) { 29 | style.styleSheet.cssText = text; 30 | } else { 31 | style.textContent = text; 32 | } 33 | 34 | // Test if media query is true or false 35 | return info.width === '1px'; 36 | } 37 | }; 38 | } 39 | 40 | return function(media) { 41 | return { 42 | matches: styleMedia.matchMedium(media || 'all'), 43 | media: media || 'all' 44 | }; 45 | }; 46 | }()); 47 | -------------------------------------------------------------------------------- /tests/test-helper.js: -------------------------------------------------------------------------------- 1 | (function(){ 2 | 'use strict'; 3 | var source = document.createElement('source'); 4 | var requestAnimationFrame = window.requestAnimationFrame || setTimeout; 5 | window.createBeforeEach = function(params){ 6 | params = $.param(params || {}); 7 | return function(){ 8 | var that = this; 9 | this.promise = $.Deferred(); 10 | this.$iframe = $('#test-iframe'); 11 | 12 | 13 | this.$iframe.css({width: 300, height: 300}); 14 | 15 | this.$iframe.one('load', function(){ 16 | that.promise.resolveWith(that, [that.$iframe.prop('contentWindow').jQuery, that.$iframe.prop('contentWindow')]); 17 | }); 18 | 19 | this.$iframe.prop('src', 'test-files/content-file.html?'+params); 20 | }; 21 | }; 22 | 23 | window.createPicture = function($, srces){ 24 | var $picture = $(''); 25 | $.each(srces, function(i, attrs){ 26 | var $elem; 27 | if(i >= srces.length -1){ 28 | $elem = 'img'; 29 | } else { 30 | $elem = 'source'; 31 | } 32 | $elem = $('<' + $elem + '/>'); 33 | $picture.append($elem); 34 | $elem.attr(attrs); 35 | }); 36 | return $picture; 37 | }; 38 | window.cleanUpDensity = function(ar){ 39 | (ar || []).forEach(function(obj){ 40 | if(obj.d){ 41 | delete obj.d; 42 | } 43 | if(obj.cached){ 44 | delete obj.cached; 45 | } 46 | }); 47 | return ar; 48 | }; 49 | 50 | window.isTrident = /rident/.test(navigator.userAgent); 51 | window.bustedSrcset = (('srcset' in document.createElement('img')) && !('sizes' in document.createElement('img'))); 52 | window.supportsPicture = !window.bustedSrcset && window.HTMLPictureElement; 53 | window.afterUnveil = (function(){ 54 | return function(fn, delay){ 55 | setTimeout(function(){ 56 | requestAnimationFrame(function(){ 57 | setTimeout(fn,0); 58 | }); 59 | }, delay || 9); 60 | }; 61 | })(); 62 | })(); 63 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | // Change this to match your project 3 | "include": ["lazysizes.js"], 4 | "compilerOptions": { 5 | // Tells TypeScript to read JS files, as 6 | // normally they are ignored as source files 7 | "allowJs": true, 8 | // Generate d.ts files 9 | "declaration": true, 10 | // This compiler run should 11 | // only output d.ts files 12 | "emitDeclarationOnly": true, 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /types/global.d.ts: -------------------------------------------------------------------------------- 1 | import { LazySizesConfigPartial, LazySizesConfig } from './lazysizes-config'; 2 | 3 | export { LazySizesConfigPartial, LazySizesConfig }; 4 | 5 | export interface LazyUnveilReadEvent extends CustomEvent { 6 | target: Element; 7 | type: 'lazyunveilread'; 8 | detail: { 9 | instance: any; // lazySizes 10 | [key: string]: any; 11 | } 12 | } 13 | 14 | export interface LazyBeforeUnveilEvent extends CustomEvent { 15 | target: Element; 16 | type: 'lazybeforeunveil'; 17 | preventAble: true; 18 | detail: { 19 | instance: any; // lazySizes 20 | [key: string]: any; 21 | } 22 | } 23 | 24 | export interface LazyBeforeSizesEvent extends CustomEvent { 25 | type: 'lazybeforesizes'; 26 | detail: { 27 | width: number; 28 | dataAttr: boolean; 29 | instance: any; // lazySizes 30 | [key: string]: any; 31 | } 32 | } 33 | 34 | declare global { 35 | interface Window { 36 | lazySizesConfig?: LazySizesConfigPartial; 37 | } 38 | 39 | interface WindowEventMap { 40 | lazyunveilread: LazyUnveilReadEvent; 41 | lazybeforeunveil: LazyBeforeUnveilEvent; 42 | lazybeforesizes: LazyBeforeSizesEvent; 43 | } 44 | 45 | interface DocumentEventMap { 46 | lazyunveilread: LazyUnveilReadEvent; 47 | lazybeforeunveil: LazyBeforeUnveilEvent; 48 | lazybeforesizes: LazyBeforeSizesEvent; 49 | } 50 | 51 | interface ElementEventMap { 52 | lazyunveilread: LazyUnveilReadEvent; 53 | lazybeforeunveil: LazyBeforeUnveilEvent; 54 | lazybeforesizes: LazyBeforeSizesEvent; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /types/lazysizes-config.d.ts: -------------------------------------------------------------------------------- 1 | export interface LazySizesConfig { 2 | lazyClass: string; 3 | loadedClass: string; 4 | loadingClass: string; 5 | preloadClass: string; 6 | errorClass: string; 7 | //strictClass: 'lazystrict'; 8 | autosizesClass: string; 9 | fastLoadedClass: string; 10 | iframeLoadMode: 0 | 1; 11 | srcAttr: string; 12 | srcsetAttr: string; 13 | sizesAttr: string; 14 | preloadAfterLoad: boolean; 15 | minSize: number; 16 | customMedia: Record; 17 | init: boolean; 18 | /** 19 | * Must be over 1. 20 | */ 21 | expFactor: number; 22 | hFac: number; 23 | loadMode: 0 | 1 | 2 | 3; 24 | loadHidden: boolean; 25 | ricTimeout: number; 26 | throttleDelay: number; 27 | [key: string]: any; 28 | } 29 | 30 | export type LazySizesConfigPartial = Partial; 31 | --------------------------------------------------------------------------------