The srcset
with the sizes
attribute is definitely the way to go to create responsive, flexibel, adaptive images.
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.
Unfortunately this demo makes only sense, if you are using a retina device. Maybe come back with one (tablet / smartphone)? Sorry!
51 |data-optimumx
attributeany kind of content you want to be unveiled
70 | 71 |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;dNothing Twitter is doing is working https://t.co/s0FppnacwK pic.twitter.com/GK9MRfQkYO
— The Verge (@verge) April 26, 2016