diff --git a/frappe/public/scss/website.scss b/frappe/public/scss/website.scss index 2c22a7f571..d4521496ba 100644 --- a/frappe/public/scss/website.scss +++ b/frappe/public/scss/website.scss @@ -95,3 +95,8 @@ img { width: 1.5rem; height: 1.5rem; } + +.lazy-image { + height: 300px; + background-color: $light; +} diff --git a/frappe/website/js/website.js b/frappe/website/js/website.js index 7fa29991d0..e056e5b57c 100644 --- a/frappe/website/js/website.js +++ b/frappe/website/js/website.js @@ -329,6 +329,45 @@ $.extend(frappe, { }, add_switch_to_desk: function() { $('.switch-to-desk').removeClass('hidden'); + }, + setup_lazy_images: function() { + // Use IntersectionObserver to only load images that are visible in the viewport + // Fallback for browsers that don't support it + // To use this feature, instead of adding an img tag, add + //
+ + function replace_with_image(target) { + const $target = $(target); + const attrs = $target.data(); + const data_string = Object.keys(attrs) + .map(key => `${key}="${attrs[key]}"`) + .join(' '); + $target.replaceWith(``); + } + + if (!window.IntersectionObserver) { + $('.lazy-image').each((_, el) => { + replace_with_image(el); + }); + return + } + + const io = new IntersectionObserver( + entries => { + entries.forEach(e => { + if (e.intersectionRatio > 0) { + io.unobserve(e.target); + replace_with_image(e.target); + } + }); + }, { + threshold: [0, 0.2, 0.4, 0.6], + }); + + $('.lazy-image').each((_, el) => { + // Start observing an element + io.observe(el); + }); } }); @@ -384,6 +423,7 @@ $(document).ready(function() { } frappe.render_user(); + frappe.setup_lazy_images(); $(document).trigger("page-change"); });