Pergunta

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&amp;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

Foi útil?

Solução

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>

Outras dicas

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"); });
});
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top