Speed up page load by deferring images
-
01-07-2021 - |
Question
I am creating a page which will contain a lot of large sized images, so naturally I want to make sure the page loads without too much trouble. I read this article here http://24ways.org/2010/speed-up-your-site-with-delayed-content
The method of deferring is as follows (pulled from page, don't mind the URL)
<div>
<h4>
<a href="http://allinthehead.com/" data-gravatar-hash="13734b0cb20708f79e730809c29c3c48">
Drew McLellan
</a>
</h4>
</div>
then later a snippet of js takes care of the image loading
$(window).load(function() {
$('a[data-gravatar-hash]').prepend(function(index){
var hash = $(this).attr('data-gravatar-hash')
return '<img width="100" height="100" alt="" src="http://www.gravatar.com/avatar.php?size=100&gravatar_id=' + hash + '">'
});
});
I don't plan on doing this for every image but definitely for some image which I don't need it to show up at page load time.
Is this the best way to go or are there better ways to achieve faster page load by deferring images?
Thanks
La solution
A little late, but in case it benefits others, there is a great article on this topic by Patrick Sexton https://varvy.com/pagespeed/defer-images.html
He basically is suggesting the same thing, only by using tiny base 64 encoded images, he can place his image tags directly in the HTML which has the benefit of being able to control attributes like height, width, alt, etc individually. It will be a lot easier to maintain your HTML this way as opposed to creating the entire image tag in a script.
<img src="data:image/png;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs=" data-src="image1.jpg" alt="image 1">
<img src="data:image/png;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs=" data-src="image2.jpg" alt="image 2">
Then your script is simple and generic for all images
<script>
function init() {
var imgDefer = document.getElementsByTagName('img');
for (var i = 0; i < imgDefer.length; i++) {
if (imgDefer[i].getAttribute('data-src')) {
imgDefer[i].setAttribute('src',imgDefer[i].getAttribute('data-src'));
}
}
}
window.onload = init;
</script>
Autres conseils
This seems to be pretty clean way of deferring images. The only potential problem is if images carry important information as "Data attributes are a new feature in HTML5".
Another option could be to put images to end of body and use CSS to position them. Personally I would stick to javascript.
Here's a version showcasing .querySelectorAll
:
function swapSrcAttributes(source) {
return function(element) {
element.setAttribute('src', element.getAttribute(source));
}
}
function forEach(collection, partial) {
for (var i = 0; i < collection.length; i++) {
partial(collection[i]);
}
}
function initDeferImages() {
// for images
var deferImages = document.querySelectorAll('img[data-src]');
// or you could be less specific and remove the `img`
deferImages = document.querySelectorAll('[data-src]');
forEach(deferImages, swapSrcAttributes('data-src'));
}
window.onload = function() {
initDeferImages();
}
Here is the compatibility table for .querySelector
and .querySelectorAll
via https://caniuse.com/#feat=queryselector
Html
<img
width="1024"
src="https://placehold.it/64x48.jpg"
data-src-defer="https://images.unsplash.com/photo-1570280406792-bf58b7c59247?ixid=MXwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=1486&q=80"
alt="image 1"
/>
<img
width="1024"
src="https://placehold.it/64x48.jpg"
data-src-defer="https://images.unsplash.com/photo-1557053964-d42e8e29cb27?ixid=MXwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=1500&q=80"
alt="image 2"
/>
JS
function deferImgs() {
Array
.from(document.querySelectorAll("img[data-src-defer]"))
.forEach((element) => {
element.setAttribute("src", element.dataset.srcDefer);
});
}
window.addEventListener("load", deferImgs());
================================================================
I'm trying to comply with Farrukh's request with this edit.
I try to do my best, but English is unfortunately only the third language I speak. And I am not a language genius. :D
This js code snippet illustrates a delayed load of some big pictures. This is not a practical implementation. The size difference between the images is intentionally huge. This is because the test must be illustrative. You can monitor its operation through a browser development tool page. F12 > Network tab > Speed settings dropdown The ideal network speed for the test is between 1 - 3MB/s (Some slow network speed). You may want to run the test several times, so you can see, that the order in which the images are loaded is not controlled in this case, but depends on the transmission. Because it is not regulated, it is not possible to predict, which image will arrive first.
We load first a small image into a large placeholder. (image: 64x48.jpg > placeholder width="1024").
The querySelectorAll() method returns a static nodelist. This list of nodes at first glance looks like an array, but it's not.
This is an array-like object:
document.querySelectorAll("img[data-src-defer]")
The Array.from() method can creates a new array instance from this object. The forEach method can now be executed on this array. The forEach() method executes a provided function once for each element of the array.
In this case, each element of the array is passed once to this function:
(element) => {
element.setAttribute("src", element.dataset.srcDefer);
}
and this function sets the value of the src="" attribute of the image tag, to the value of the dataset of the same image tag.
src="https://placehold.it/64x48.jpg";
data-src-defer="https://images.unsplash.com/photo-1570280406792-bf58b7c59247?ixid=MXwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=1486&q=80";
src = data-src-defer;
So finally:
src="https://images.unsplash.com/photo-1570280406792-bf58b7c59247?ixid=MXwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=1486&q=80";
You can do it as simple as the example below:
All images have data-src
attribute where you put the file path. And src
attribute with a fake transparent 1x1px png image. You can also add loading
attribute setted to lazy
, it tells modern browsers to avoid to load immediately the images that are out of viewport (visible site zone)
<img data-src="path/to/image.jpg" loading="lazy"
src="data:image/png;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs=" />
Add this script to make all images get the src
attribute once your site is loaded (you need jQuery to make it work)
$(function(){
$("img[data-src]").attr("src", function(){ return $(this).data("src"); });
});