luis-almeida / unveil

A very lightweight jQuery plugin to lazy load images
4.15k stars 676 forks source link

Unveil starts before preview images are loaded #22

Open netAction opened 11 years ago

netAction commented 11 years ago

When we have a page like this, unveil starts unveiling all images. But maybe just the first is inside the window after loading:

<img src="image1.jpg" ... />
<img src="image2.jpg" ... />
<img src="image3.jpg" ... />
<img src="image4.jpg" ... />

Second problem: We cause lots of traffic before the page is completely loaded. So let's start unveil when the small images are already there.

Instead of

$w.scroll(unveil);
$w.resize(unveil);
unveil();

I use this:

$w.scroll(unveil);
$w.resize(unveil);
images.one('load', function() {
    $w.trigger('scroll');
}).each(function() {
  if(this.complete) {
    $(this).trigger('load');
  }
});

Now there is still a bug: image2 unveils after loading even if it is kicked off the screen by image1. Unveil shoud start after all thumbnails are loaded. Maybe you have a better solution.

mjau-mjau commented 11 years ago

Unveil will start to load the designated image regardless if the "preview" image is already loaded or not. The whole point of unveil, is to load an image if it is within viewers viewport, and it does just that. There is no concept of "preview image", but the image should be empty or a placeholder ...

If Unveil starts unveiling more images initially, that is normally because you have not set a width or height in the image attributes (or with CSS). Failure to do this means that on initial page body load, a lot of zero-height images are within the viewport and will start to be loaded with unveil (as they should be). To avoid this problem, set a height to your images, or use a placeholder image with a relative height.

netAction commented 11 years ago

Setting the height for images is very unusual, especially when it comes to responsive design. You think, we should calculate the aspect ratio and write it down in CSS?

mjau-mjau commented 11 years ago

You are right, and it has been written a lot about this lately in many blogs, with some solutions. If you cannot use width/height as with responsive designs, there are two problems with lazy loaders like unveil:

The way to solve it, is to use a placeholder image that represents the same aspect as the image that is to be loaded. In my case, I am loading images at 3:2 aspect ratio, so I am just using a transparent 3x2 Gif file ... In a responsive design, the image would be set to 100% so it will scale to fill the same area as the unveiled image.

There is an even better method using a padding-hack, as explained here: http://mobile.smashingmagazine.com/2013/09/16/responsive-images-performance-problem-case-study/

Both cases require that you know the size or aspect of the images that are going to be loaded, possibly through a CMS where image width/height properties can be accessed. If you do not know the size/aspect of the images that are being loaded, your best solution would be to simply add a 1px gif as placeholder. It will scale to a square to fit in the design, although the unveiled image may change dimensions. You will avoid your problem with all images being loaded initially, and the 'jumping' effect will be less conspicuous (although it will still exist).

netAction commented 11 years ago

That does not work as the GIF might load too slow. This is what I described in my initial post.

mjau-mjau commented 11 years ago

what do you mean 'might' load to slow? Unveil doesn't even initiate until body load, which is after all your images are loaded so not sure how that will not work ...

Besides, to get even more advanced, you should just use a data-URI instead of loading an external gif anyway:

<img src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7">

The above code represents a 1px transparent GIF.

Trust me, I have dealt with the exact same issues you are having ...

mjau-mjau commented 11 years ago

Keep in mind, for this to work in your responsive design, you need to make sure the image is set not only to max-width:100% (like some responsive designs rely on), but also width:100%;

width:100%;
max-width:100%;

The above code will scale all images to 100% of the container, and prevent them from scaling beyond the container. It will also allow the 1px gif to scale up and maintain aspect ratio.

netAction commented 11 years ago

Runs when images are loaded:

$( window ).load(function() { ... })

Runs before images are loaded:

$( document ).ready()
mjau-mjau commented 11 years ago

... then just run the unveil function on $(window).load(), or use the data-URI gif, supposedly both ...

netAction commented 11 years ago

$(window).load() might be a good solution on most of the pages.