I am currently working on a site for a holiday apartments business in Devon (You can see the site in development here: http://beta.vomero.co.uk).
The problem
Because of the nature of the business, high quality photography and showing lots of images of what to expect on your stay are really important. However the time taken to download all these images can slow the page from loading.
The solution
The solution is to load the images once the body of the page has loaded - in a similar way how the iPhone does things - show the raw information quickly, then flesh it out with images afterwards.
The basic idea is to ensure that the space for the image is allocated correctly (to avoid layout problems whilst the image loads) and to initially display a small animated icon (such as one from preloaders.net) until the 'real' image is ready to be displayed.
The best way of doing this seems to be adding an extra element to the page which can have the background set as the animated .gif - This way you can have the animation appear at 100% size in the centre of the block, rather than having it stretch to the width of you real image.
Existing methods
There are several solutions floating around for methods of doing this, but none were suitable for me to use for this site. I need to be able to declare the image source within the HTML and not as a variable within a JavaScript file. Other solutions seemed to use non-standard attributes to store the url for the 'real' image, but I wanted to ensure that the home page passed the W3C Validator.
Many other methods also required adding extra mark-up to your page which I was keen to avoid.
My jQuery method
My method doesn't require any additional HTML elements to be added, instead we use the wrap and unwrap functions to do all the hard work for us - These were added to the framework in version 1.4
Requirements:
-
A loading animation
-
A 1x1 transparent gif
-
And of course the jQuery framework (v1.4+ for wrap and unwrap functions)
We then add an image to our page in this way:
<img src="/images/blank.gif" height="200" width="300" class="delayLoad" onmouseover="this.src = '/photos/myphoto.jpg'" />
Then add a CSS class to display out loading animation:
.delayLoad {
background: url('images/loading.gif') no-repeat 50% 50%;
}
So this would now work, and display the image when the user hovers their mouse over the image, but let's use jQuery to find all these images and execute the mosueover function for us.
// Load images once the page has loaded
jQuery("img.delayLoad").each(function() {
// Create a new span element which we will wrap around our image
// Using a span because if the image was inside an <a> tag then online inline elements should be used
var delaySpan = document.createElement("span");
with (jQuery(this)) {
// Handle images that are hidden, otherwise display mode for the span should be block (inline doesn't work properly)
if (css('display') == 'none') {
var _display = 'none' } else {
var _display = 'block' }
// Copy the style from the image into a new object (this means you don't need to worry about styling this span within your CSS)
var cssObj = {
'height' : css('height'),
'width' : css('width'),
'margin-top' : css('margin-top'),
'margin-right' : css('margin-right'),
'margin-bottom' : css('margin-bottom'),
'margin-left' : css('margin-left'),
'background-image' : css('background-image'),
'background-color' : css('background-color'),
'background-repeat' : css('background-repeat'),
// Hack for now, becuase IE doesn't seem to read the background-position property correctly
'background-position' : '50% 50%',
'display' : _display
}
}
// Apply our style properties to our span
jQuery(delaySpan).css(cssObj);
// Wrap the image in the span
jQuery(this).wrap(delaySpan)
// Hide the image (leaving just the span visible
.hide()
// Simulate the mouse over the image, whcih will cause it to switch the img src
.mouseover()
// Remove the mouseover attribute (since we don't want to update the img src every time the user does a mouseover
.removeAttr("onmouseover")
// Simulate the mouse moving out of the image (To reset the image to its normal state)
.mouseout()
// Once the image is loaded, perform a function
.load(function () {
// Fade the image in
// Remove the span by unwrapping the image
jQuery(this).fadeIn().unwrap();
});
});
Test it
I found using Firefox Throttle really handy to slow things down, whilst keeping an eye on the Firebug net panel, to see exactly what was happening as the page loads.
Limitations
As with all of these techniques to load images after the DOM is ready, search engine crawlers, or browsers without JavaScript enabled are not going to see your 'real' images. But I just don't see a way around this - if you include the 'real' image url in the DOM then it will get loaded alongside the rest of the page content, causing a possible delay in the page being shown to the user.
Why not just use the onload event and save the necessity for jQuery? - I had tried using onload="this.src='/photos/myphoto.jpg'" but this event seemed to be firing before the rest of the DOM was ready - defeating the purpose of what we are doing.
I hope this helps, let me know your thoughts.