Improvements to Lazy Loading

Improvements to Lazy Loading
  • Now applied to all images over 150x150px

  • Stores the width and height in the WeakMap rather than using
    percentages for accuracy

  • When oneboxed images are hidden, they are given a subtle border for better
    visibility.

  • Don’t apply when in the composer. Causes flickering.

diff --git a/app/assets/javascripts/discourse/lib/lazy-load-images.js.es6 b/app/assets/javascripts/discourse/lib/lazy-load-images.js.es6
index e390a9d..5a2b514 100644
--- a/app/assets/javascripts/discourse/lib/lazy-load-images.js.es6
+++ b/app/assets/javascripts/discourse/lib/lazy-load-images.js.es6
@@ -2,7 +2,10 @@ const OBSERVER_OPTIONS = {
   rootMargin: "50%" // load images slightly before they're visible
 };
 
-const imageSources = new WeakMap();
+// Min size in pixels for consideration for lazy loading
+const MINIMUM_SIZE = 150;
+
+const hiddenData = new WeakMap();
 
 const LOADING_DATA =
   "data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==";
@@ -12,7 +15,12 @@ function hide(image) {
   image.classList.add("d-lazyload");
   image.classList.add("d-lazyload-hidden");
 
-  imageSources.set(image, { src: image.src, srcset: image.srcset });
+  hiddenData.set(image, {
+    src: image.src,
+    srcset: image.srcset,
+    width: image.width,
+    height: image.height
+  });
   image.removeAttribute("srcset");
 
   image.src = image.dataset.smallUpload || LOADING_DATA;
@@ -21,9 +29,9 @@ function hide(image) {
 
 // Restore an image when onscreen
 function show(image) {
-  let sources = imageSources.get(image);
+  let imageData = hiddenData.get(image);
 
-  if (sources) {
+  if (imageData) {
     const copyImg = new Image();
     copyImg.onload = () => {
       image.src = copyImg.src;
@@ -35,14 +43,14 @@ function show(image) {
       copyImg.onload = null;
     };
 
-    copyImg.src = sources.src;
-    copyImg.srcset = sources.srcset || copyImg.srcset;
+    copyImg.src = imageData.src;
+    copyImg.srcset = imageData.srcset || copyImg.srcset;
 
     copyImg.style.position = "absolute";
     copyImg.style.top = 0;
     copyImg.style.left = 0;
-    copyImg.style.height = "100%";
-    copyImg.style.width = "100%";
+    copyImg.style.width = imageData.width;
+    copyImg.style.height = imageData.height;
 
     image.parentNode.appendChild(copyImg);
   } else {
@@ -62,10 +70,15 @@ export function setupLazyLoading(api) {
     });
   }, OBSERVER_OPTIONS);
 
-  api.decorateCooked($post => {
-    $(".lightbox img", $post).each((_, img) => {
-      hide(img);
-      observer.observe(img);
-    });
-  });
+  api.decorateCooked(
+    $post => {
+      $("img", $post).each((_, img) => {
+        if (img.width >= MINIMUM_SIZE && img.height >= MINIMUM_SIZE) {
+          hide(img);
+          observer.observe(img);
+        }
+      });
+    },
+    { onlyStream: true }
+  );
 }
diff --git a/app/assets/stylesheets/common/base/lightbox.scss b/app/assets/stylesheets/common/base/lightbox.scss
index 9ddc6e9..1c1e46a 100644
--- a/app/assets/stylesheets/common/base/lightbox.scss
+++ b/app/assets/stylesheets/common/base/lightbox.scss
@@ -13,6 +13,10 @@
   box-sizing: border-box;
 }
 
+.onebox img.d-lazyload-hidden {
+  border: 1px solid $primary-low;
+}
+
 .cooked img.d-lazyload {
   transition: opacity 0.4s 0.75s ease;
 }

GitHub
sha: 0e710dc5

2 Likes

This commit has been mentioned on Discourse Meta. There might be relevant details there:

https://meta.discourse.org/t/new-feature-lazy-loading-images/104690/14