├── README.md ├── img ├── dog-battersea.jpg ├── dog-battersea.svg ├── dog-face.jpg ├── dog-face.svg ├── dog-running.jpg └── dog-running.svg ├── index.html ├── lazy-load.js ├── lazy-load.min.js └── package.json /README.md: -------------------------------------------------------------------------------- 1 | # Lazy Load - Intersection Observer 2 | A library to lazy load images using Intersection Observer 3 | 4 | ## Details 5 | 6 | If you'd like to learn more about this code, I've written up a full blog post on my [blog](https://deanhume.com/Home/BlogPost/lazy-loading-images-using-intersection-observer/10163). 7 | 8 | This library was also featured on the [2017 Performance Calendar](https://calendar.perfplanet.com/2017/progressive-image-loading-using-intersection-observer-and-sqip/) - for more details, please see this [link](https://calendar.perfplanet.com/2017/progressive-image-loading-using-intersection-observer-and-sqip/). 9 | 10 | 11 | For a live demo, please visit [deanhume.github.io/lazy-observer-load](https://deanhume.github.io/lazy-observer-load). 12 | -------------------------------------------------------------------------------- /img/dog-battersea.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/deanhume/lazy-observer-load/6b0a5b4ff2e4d2fee77e622b5d475e46a75ca889/img/dog-battersea.jpg -------------------------------------------------------------------------------- /img/dog-battersea.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /img/dog-face.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/deanhume/lazy-observer-load/6b0a5b4ff2e4d2fee77e622b5d475e46a75ca889/img/dog-face.jpg -------------------------------------------------------------------------------- /img/dog-face.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /img/dog-running.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/deanhume/lazy-observer-load/6b0a5b4ff2e4d2fee77e622b5d475e46a75ca889/img/dog-running.jpg -------------------------------------------------------------------------------- /img/dog-running.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Lazy Loading images using Intersection Observer 7 | 8 | 31 | 32 | 33 | 34 | 35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
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 | 90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 |
176 |
177 |
178 |
179 |
180 |
181 |
182 |
183 |
184 |
185 |
186 |
187 |
188 |
189 |
190 |
191 | 192 | 196 | 197 | 198 | 199 | -------------------------------------------------------------------------------- /lazy-load.js: -------------------------------------------------------------------------------- 1 | const defaults = { 2 | imageLoadedClass: 'js-lazy-image--handled', 3 | imageSelector: '.js-lazy-image', 4 | // If the image gets within 50px in the Y axis, start the download. 5 | rootMargin: '50px 0px', 6 | threshold: 0.01 7 | }; 8 | 9 | let config, 10 | images, 11 | imageCount, 12 | observer; 13 | 14 | /** 15 | * Fetches the image for the given URL 16 | * @param {string} url 17 | */ 18 | function fetchImage(url) { 19 | return new Promise((resolve, reject) => { 20 | const image = new Image(); 21 | image.src = url; 22 | image.onload = resolve; 23 | image.onerror = reject; 24 | }); 25 | } 26 | 27 | /** 28 | * Preloads the image 29 | * @param {object} image 30 | */ 31 | function preloadImage(image) { 32 | const src = image.dataset.src; 33 | if (!src) { 34 | return; 35 | } 36 | 37 | return fetchImage(src).then(() => { applyImage(image, src); }); 38 | } 39 | 40 | /** 41 | * Load all of the images immediately 42 | * @param {NodeListOf} images 43 | */ 44 | function loadImagesImmediately(images) { 45 | // foreach() is not supported in IE 46 | for (let i = 0; i < images.length; i++) { 47 | let image = images[i]; 48 | preloadImage(image); 49 | } 50 | } 51 | 52 | /** 53 | * Disconnect the observer 54 | */ 55 | function disconnect() { 56 | if (!observer) { 57 | return; 58 | } 59 | 60 | observer.disconnect(); 61 | } 62 | 63 | /** 64 | * On intersection 65 | * @param {array} entries 66 | */ 67 | function onIntersection(entries) { 68 | // Disconnect if we've already loaded all of the images 69 | if (imageCount === 0) { 70 | disconnect(); 71 | return; 72 | } 73 | 74 | // Loop through the entries 75 | for (let i = 0; i < entries.length; i++) { 76 | let entry = entries[i]; 77 | // Are we in viewport? 78 | if (entry.intersectionRatio > 0) { 79 | imageCount--; 80 | 81 | // Stop watching and load the image 82 | observer.unobserve(entry.target); 83 | preloadImage(entry.target); 84 | } 85 | } 86 | } 87 | 88 | /** 89 | * Apply the image 90 | * @param {object} img 91 | * @param {string} src 92 | */ 93 | function applyImage(img, src) { 94 | // Prevent this from being lazy loaded a second time. 95 | img.classList.add(config.imageLoadedClass); 96 | img.src = src; 97 | } 98 | 99 | let LazyLoad = { 100 | 101 | init: (options) => { 102 | config = {...defaults, ...options}; 103 | 104 | images = document.querySelectorAll(config.imageSelector); 105 | imageCount = images.length; 106 | 107 | // If we don't have support for intersection observer, loads the images immediately 108 | if (!('IntersectionObserver' in window)) { 109 | loadImagesImmediately(images); 110 | } else { 111 | // It is supported, load the images 112 | observer = new IntersectionObserver(onIntersection, config); 113 | 114 | // foreach() is not supported in IE 115 | for (let i = 0; i < images.length; i++) { 116 | let image = images[i]; 117 | if (image.classList.contains(config.imageLoadedClass)) { 118 | continue; 119 | } 120 | 121 | observer.observe(image); 122 | } 123 | } 124 | } 125 | }; 126 | 127 | export default LazyLoad; 128 | -------------------------------------------------------------------------------- /lazy-load.min.js: -------------------------------------------------------------------------------- 1 | 'use strict';var _extends=Object.assign||function(a){for(var c,b=1;b