I’m not sure if this is the right place to post this but I have a ‘gallery’ type page that has to load around 40 images (all 1920 x 1080) and the page is taking ages (around 20 seconds) to load. I came across a couple of site which do what I want but don’t have a huge grasp on JS so am not sure how to do it myself and would be grateful for any help please.
Have you tried testing your site in gtmetrix.com ? I tried and gave up it took so long. If you can get it to finish it should give you some ideas as to what needs attention.
Thanks I’ll have a look, I think I know what the issue is though (the images are around1mb each), I’m just not sure how to fix it. I know that if I reduce the image size it’ll speed it up but then they’ll look blurry and the client wants the images to be sharp to show their work clearly.
Maybe try AmpProject.org which is very good at loading images. It is essential to ensure the page validates in order to get the full benefit but is well worth the effort because Google caches valid web pages.
Online example page with over a dozen images each about a meg each:
If you are only showing thumbnails to begin with, there is no need to be loading the full size images on page load. They can be deferred or loaded on request.
I think I understand what you’re saying, are you saying that I can load small images for different devices? For example if somebody is on a phone then they will probably only need an image to be 475px wide, but on a retina display they will need the full 1920px width.
A common way – especially for large image galleries – would be not to load all images from the start, but only when they actually entered the viewport; this is called “lazy loading”. A basic example might look like this:
Note that the images don’t have the src attribute set from the start, but instead stored as a data-lazy-src attribute (can be called anything) which will be applied when they get scrolled into the viewport:
const images = document.querySelectorAll('[data-lazy-src]')
const imgArray = Array.from(images)
const checkImage = (image, index) => {
// Check if the image entered the vieport
if (image.getBoundingClientRect().top < window.innerHeight) {
// Set the actual source of the image
image.src = image.dataset.lazySrc
// Remove it from the array to exclude it
// from future checks
imgArray.splice(index, 1)
}
}
const scrollHandler = () => {
// On each scroll event, iterate over the
// images and check their position
imgArray.forEach(checkImage)
if (!imgArray.length) {
// When there are no images left to lazy-load,
// listening to the scroll event is no longer
// required and we can free the resource
window.removeEventListener('scroll', scrollHandler)
}
}
// Bind the scroll handler
window.addEventListener('scroll', scrollHandler)
// Also check the images initially
imgArray.forEach(checkImage)
Here’s a pen. You could improve this by loading the images when they come near to the viewport by a certain amount of pixels, and improve performance by debouncing the scroll handler to only check the images when the user finished scrolling.
This is possible too by using a srcset instead of a plain src attribute – here’s a useful article on responsive images:
These two techniques can of course be combined; you’d then just store the srcset as a (say) data-lazy-srcset attribute.
I’ve created a new set of images and tried to load different sizes for different screen sizes but it doesn’t seem to be working. I’ve got the load time down to 10 seconds but I don’t think the lazy loading is working.
I can’t tell you why lazy loading is not working but I can tell you that if you run your page through gtmetrix as I suggested earlier you will find a number of other matters that need addressing in order to speed up your site.
I have been through that and speeded it up quite a lot over what it was, it’s still really slow. I did try to do the ‘gzip compression’ but when I added the code to the .htaccess file I just got a 500 error so had to undo that
The biggest saving you’re going to get as shown in your gtmetrix report is to optimise your images. You need to do that as well as lazy loading, not instead of.
The example from @m3g4p0p was for single images not srcsets and will not work unless the code is modified (which is beyond my skills). You missed the data attributes anyway (data-lazy-src).
Yes, as @PaulOB says you’ll have to set the .srcset properties of the images then, not .src; the line I commented with // Set the actual source of the image thus becomes
image.srcset = image.dataset.lazySrcset
The name of the dataset property does not matter, you might also leave it as is – it just has to match the corresponding data-attribute in the markup. You might check out this article on the MDN for some details on how to access data-attributes with JS. And of course, if you have trouble understanding the above code just let me know and I’ll try to explain. :-)