In this blog, I am going tell you the quickest and easiest way to create lazy loading without using any libraries.We are just going to use simpleCSS
and JavaScript
The Concept
We first add the lightweight image URL in the src
and srset
attributes, and the actual image URL and actual srcset
into data-src and data-srcset
respectively.
On initial page load, on window resize, scroll and change in orientation we call the lazyload()
with debounce
.
The lazy load function loops through each image on the page and checks if its in the viewport .
If it is in the viewport, takes the original image URLs from the data-src
and data-srcset
attributes and replace the lightweight image with the original one, so we get a blur
effect.
We will also add a image container with off-white
background and a proper set height( using padding in % ) so it shows when while the images are being loaded.
How can we achieve lazy-load?
PHP
We can register the custom thumbnails like lazy-12x8
for the post and then regenerate thumbnails using Regenerate thumbnail plugin .
functions.phpfunction lazy_load_setup() { add_image_size( 'lazy-12x8', 12, 8, array( 'center', 'center' ) );}add_action( 'after_setup_theme', 'lazy_load_setup' );
Now inside our page e.g. index.php
<?php
/* Start the Loop */
while ( have_posts() ) : the_post(); $img_src_array = wp_get_attachment_image_src( get_post_thumbnail_id( get_the_ID() ), 'full' );
$img_src_lightweight_array = wp_get_attachment_image_src( get_post_thumbnail_id( get_the_ID() ), 'lazy-12x8' );
$img_srcset = wp_get_attachment_image_srcset( get_post_thumbnail_id( get_the_ID() ) ); ?>
<div class="post-container">
<h3><?php the_title(); ?></h3>
<?php if ( has_post_thumbnail() ) {
?>
<div class="lazy-image">
<div class="thumbnail">
<?php
echo wp_get_attachment_image(
get_post_thumbnail_id( get_the_ID() ),
'full',
false,
[
'data-src' => esc_url( $img_src_array[0] ),
'data-srcset' => $img_srcset,
'src' => esc_url( $img_src_lightweight_array[0] ),
'alt' => esc_html( get_the_title() ),
'srcset' => esc_url( $img_src_lightweight_array[0] ),
]
)
?>
</div>
</div>
<?php
}
?>
</div>
<?phpendwhile;
<?php
Styles
.lazy-image {
height: 0;
padding-bottom: 62.25%;
position: relative;
}.lazy-image .thumbnail {
margin: 0 auto;
overflow: hidden;
position: absolute;
background-color: #f5f5f5;
height: 100%;
width: 100%;
top: 0;
left: 0;
}.lazy-image .thumbnail img {
min-width: auto;
min-height: auto;
width: 100%;
height: 100%;
-o-object-fit: cover;
object-fit: cover;
position: absolute;
left: 50%;
top: 50%;
-webkit-transform: translate(-50%, -50%);
transform: translate(-50%, -50%);
}
JavaScript
Lets write a debounce function in so that lazyload
function does not get called repeatedly when the scrollevent
is fired.
main.js/*
* Calls the given function after the given interval.
*
* @param {Object} func Function name.
* @param {number} wait Time in milliseconds.
*
* @return {Function} Debounced function.
*/
export const debounce = ( func, wait ) => { let timeout; /**
* Debounce function.
*/
return function() { const context = this,
args = arguments; /**
* Later function.
*/
const later = function() {
timeout = null;
func.apply( context, args );
}; clearTimeout( timeout ); timeout = setTimeout( later, wait );
};};
Lets add lazyload
feature and also use the above debounce function created.
// When the content is loaded.
document.addEventListener('DOMContentLoaded', function() { // Get all the images on the page that have 'data-src' attribute.
let lazyloadImages = document.querySelectorAll('[data-src]'); /**
* Lazy load function.
*
* Loops through each img on the page and checks if its in the viewport.
* If it is in the viewport, takes the original image size from the 'data-src', and 'data-srcset' attributes and
* replaces the lightweight image
*/
function lazyload () { // Loop through each image on the page.
lazyloadImages.forEach(function( img ) { // Get the top position of each image.
const imgTop = img.getBoundingClientRect().top; // Check id image in Viewport ( If the image top position is less than window's inner height.
if( imgTop < window.innerHeight ) { // Get the original image size from the 'data-src' attributed and replace the lightweight image with the original one.
const dataSrc = img.getAttribute( 'data-src' );
img.setAttribute( 'src', dataSrc ); // Get the original image size from the 'data-srcset' attributed and replace the lightweight image with the original one.
const dataSrcSet = img.getAttribute( 'data-srcset' ); if ( dataSrcSet ) {
img.setAttribute( 'srcset', dataSrcSet );
}
}
}); // If there are no images on the page, remove the events.
if( 0 === lazyloadImages.length ) {
document.removeEventListener("scroll", lazyload);
window.removeEventListener("resize", lazyload);
window.removeEventListener("orientationChange", lazyload);
}
} /**
* Add events on 'scroll', 'resize' and 'orientationchange'
* Also use debounce to avoid multiple functions calls within the same time interval.
*/
document.addEventListener("scroll", debounce( lazyload, 300 ) );
window.addEventListener("resize", debounce( lazyload, 300 ));
window.addEventListener("orientationChange", debounce( lazyload, 300 )); // Call the lazyload() first time the window loads.
lazyload();});
And that’s it. When all you have to do is just used the same structure with where-ever you want the lazy load. You can also implement the similar approach in any non WordPress site which just uses HTML and CSS with JavaScript.
If you like my work, please star my git repo to support me and please follow me on : 🙏
Twitter — @imranhsayed
Github — imranhsayed