I’ve been admiring the ‘image loading…’ and subsequent fade-in of (spectacular) photos on Couloir. Go and have a quick look then return here…
Looks like Flash doesn’t it? Yet the photo fade is performed by a JavaScript timeout changing opacity. No Flash required. The ‘image loading…’ is a div absolutely positioned directly over the photo and faded out once the page has loaded. The function is triggered by an onload and applies a gradually reducing opacity to the ‘loading’ div. Here’s a simplified code snippet to fade out a selected layer.
function fadeOut(objId,opacity) {
if (document.getElementById) {
if (opacity >= 0) {
document.getElementById(objId).style.MozOpacity = opacity/100;
opacity -= 10;
window.setTimeout("fadeOut('"+objId+"',"+opacity+")", 100);
}
}
}
For the sake of brevity, the above snippet works in Firefox and Mozilla only, but it should give you a decent idea of the approach. As soon as I get a moment, I’ll stick together an accessible cross-browser version and post it in the Sandbox.
Update: I’ve added the cross-browser, accessible onload image fades without Flash into the Sandbox.
Photography · DOM | JavaScript
Adam Bramwell wrote:
Well that is interesting.
It sure is a lovely site, but it would be nice if the old image was still available to look at, right up until the next image is ready.. I’m sure interested to see what you come up with.
Jeremy Keith wrote:
It works in Safari too, surprisingly.
I remember when I first came across the site (and a lovely site it is), thinking “how are they doing that?”.
Rich wrote:
Yeah, in truth this is one of the posts that has been hanging around for ages waiting for me to finish the Sandbox thing. In the end I got impatient with myself :-)
Jonathan Buchanan wrote:
How about using the CSS3 opacity property instead for forward compatibility with other browsers?
It’s been supported since 2004–02-24 with -moz-opacity being kept as an alias.
Rich wrote:
Jonathan – thanks for that. Didn’t realize opacity had made it’s way into Firefox; I know Safari supports it now, so it was going to end up in my Sandbox version. Along with -khtml-opacity for older Safari versions and filter for IE.
Richard@Home wrote:
It seems opacity is the new ‘drop shadow’ of web design :-)
add the following under document.getElementById(objId)...
document.getElementById(objId).style.filter=’ alpha(opacity=’+opacity+’)’;
Also, you will need to give your transparent element an exlicit width in your CSS for the transparency to work in IE
More here: http://richardathome.no-ip.com/index.php?article_id=384
Justin wrote:
It looks even more impressive when you cross-fade images with opacity:
http://slayeroffice.com/code/imageCrossFade/
patrick h. lauke wrote:
not to take a dump in your lovely sandbox, but your post inspired me to my own little experimentation, and turning the whole thing on its head: rather than having something in front of the image slowly fading away (which, when javascript is disabled, just leaves you with the “loading…” thing and never reveals the image), i have the image “fading up” and the loading animation as background to a container.
splintered experiments: javascript fade
major pain was to work around caching issues: when the image is already cached, the page paints before my javascript could “hide” the image initially. a lot of tweaking until i found a half-way decent (although “dirty”) solution.
i’ll write up a proper experiment description on my site later, but for the time being i’m just itching to release this to the general populace ;)
patrick h. lauke wrote:
p.s.: i’d be grateful if somebody on a mac could test it for me…
Rich wrote:
Patrick – worked fine on Safari 1.2.
What I wanted to do – and it seems I better get my arse in gear – was manipulate the DOM and create the ‘loading’ element using JavaScript. That way only JavaScript enabled browsers would get the loading div and the fade, anyone else would get the image straight off.
patrick h. lauke wrote:
rich, that was my initial thought as well, and then i decided to just take a shortcut. i think you’d still end up with the same problem i had: if you planned on running the javascript onload, there is a strong chance that your image (if it’s already in cache) will show just before your javascript occludes it, resulting in a nasty flash.
speaking of which: notice in my javascript i don’t ramp the opacity up to 1.0, but to 0.999 – this seems to work in preventing a bug in ff/mozilla where just before reaching 1.0 it flashes (as on the coulouir site).
thanks for the inspirational idea…kept me entertained this afternoon, seeing that i’m off work sick and bored out of my head…
Rich wrote:
Perhaps the way to do it is (as you did) put the loading image behind and then fade in the photo. The photo can be initially hidden from JavaScript folks (so no initial flicker) using something like:
document.write(‘<link rel=”stylesheet” type=”text/css” href=”js_hide.css” />’)
I use a similar technique for my Site contents drop down, as explained in an earlier post and more recently expanded on by Bobby van der Sluis.
patrick h. lauke wrote:
ah…but document.write does not work with xhtml when it’s properly sent as application/xhtml+xml (which i’m usually doing by selectively sending MIME types via PHP whenever possible).
see for instance http://ln.hixie.ch/?start=1091626816&count=1
if, however, you’re sticking with plain vanilla html (or sending xhtml as text/html, you naughty boy) then yes, document.write is a viable option.
Rich wrote:
OK then, hide the photo in your normal stylesheet then unhide it in a style sheet for non-JavaScript folks:
<noscript>
<link rel=stylesheet type=”text/css” href=no_js_unhide.css />
</noscript>
patrick h. lauke wrote:
last one, then i’ll butt out: the noscript idea sounded great, i even tried it…but it doesn’t quite work when javascript is off in ff. running it through the validator also produces errors a la “document type does not allow element “noscript” here; assuming missing “object” start-tag”
trying to wrap the noscript inside an object produces validation errors for the link element not being allowed there…
Rich wrote:
Frankly, I think those are failings in the validator. The XHTML Strict DTD quite clearly includes noscript in the head section. By extension therefore, any element allowed in the <head> should be allowed within a noscript in the <head> – that’s how it works in the <body>. Otherwise how do we deal with the very accessibility issues we are trying to overcome here?
I’ll double-check with the W3C mailing lists and then submit this as a bug. If it isn’t a bug, then I’ll need to pretty string convincing as to why not!
Rich wrote:
Looking closer at the XHTML DTD, in does still imply, to my understanding, that <noscript> is allowed within <head> but it does say that <noscript> should only contain block level elements.
While this is fine for when <noscript> appears within the <body> it is just plain wrong for within the <head> because no block level elements are allowed with the <head>.
Is it too late to get the spec to change – to be corrected IMO? Perhaps, but it shouldn’t be. Of course I could be entirely mistaken – please enlighten me if I am.
Chris Patterson wrote:
Great idea. Saw this Friday and knocked together an approach using background-image – looks like it’s not dissimilar from what Patrick had come up with (although I never would have figured out the ‘flash-upon-fully-opaque’ issue).
I have a draft version up and visible for the moment at http://www.brazendoxy.com/c72/fader/wonky_looper.html – the “next” link should really be generated or modified through javascript, but it’s a start.
What I’d really like to be able to do is fade-transition through an array of images without user input. I don’t want/need to iterate through the array more than once, but all my attempts this afternoon failed badly. Any feedback / suggestions / pointers from more experienced javascript folks would be greatly welcomed.
patrick h. lauke wrote:
chris, you may want to have a look at the slayeroffice example given below by justin
incidentally, that one inspired me for another experiment, which degrades gracefully when javascript is disabled (showing merely a list of images, rather than a cross-fading slideshow)
splintered experiment: javascript cross-fade
Chris Patterson wrote:
Hi Patrick –
I’d seen justin’s example. I agree that it (and your most recent example) are very well-suited for gallery-type situations.
I’m thinking of a slightly different case. What I’m aiming for is a Flash-free take on the cross-fading that Todd Dominey did for the 2003 PGA Championship redesign ( http://www.pga.com/pgachampionship/2003/ – pictures of all 18 holes crossfade in sequence). In my intended approach, the case when javascript or CSS is disabled would be either a simple slideshow or just the single image loading in.
I have an angle that I think may be viable, but I won’t have time to get anything posted until this evening.
Thanks to all the smart folks posting good resources – as a newcomer to javascript, it’s great to learn new, accessible tricks.
Jason Beaird wrote:
Great work Rich! I thought I’d try it out on the artwork gallery on my site. The only problem is that since I don’t have a specified height for my images, I cannot have a specified height for the containing div. As a result, my loading image moves around the first time the fadein image loads. Regardless, the transitional effect is very nice.
Chris Patterson wrote:
I’ve put a copy of what I’ve come up with at http://brazendoxy.com/c72/fader/iterator.html – it’s working as intended in everything I’ve looked at except Safari (v1.2.4), which has an unsightly ‘flash’ the first time through as images are about to transition. I believe it’s a caching issue as the style.backgroundImage is being set, but haven’t been clever enough to make a definitive testcase or come up with a workaround.
This version will do what I need for now, but if anyone comes up with a better approach I’m always happy to learn.
Olly Hodgson wrote:
Hoorah, after a bit of faffing (trying to make IE stop throwing error messages at me) I made it work alongside my IE-image-resize function. Yay! And I can’t even do JavaScript!
Except now the images never get past the “loading” stage in Opera. Surely they should just pop straight to visible if the browser doesn’t support opacity?
SU wrote:
Thanks to the great discussion here, I’ve been able to improve my original fade technique on Couloir. The way I solved the “does not validate issue” related to <noscript> being the in <head> was to turn the issue around.
In the default stylesheet, I HIDE the loader and show the photo. Then, using javascript in the <head>, I do a document.write to pull in a small alternate stylesheet that reverses those settings for people who have JS turned on. This way, the site still validates as XHTML 1.0 Strict, anyone with JS sees the image fade-in technique, and those without JS get the standard non-fade photo.
Now to fix those inaccessible menus…
SU wrote:
I believe I now have the <a href=”http://www.couloir.org”>Couloir menu working 100% on browsers without Javascript</a>. The solution involved PHP, rather than CSS, but mainly because I wanted to maintain functionality without destroying the experience for those with JS.
timfm wrote:
Great discussiion and techniques. Richard, would there be a way to apply the effect to a background-image in the case that one might want text on top (in front)?
sarchi wrote:
cross posted to
http://www.mandarindesign.com/2004_11_01_archive.html#110054387679060675
Jarkko wrote:
Couldn’t document.write be replaced with a set of createTextNode (for the css text), createElement, createAttribute and then node.appendChild to insert that element inside the head tag?
I haven’t tried this but I got the idea when reading this bug report
Anyway, those functions can’t produce invalid xml in the document and are therefore also allowed in application/xhtml+xml.
Kyle Bellamy wrote:
Just curious, this script (or rather the one that I followed the link from to here) allows for an image fade in. What I want to do is have this done to 12 images that are arranged in a grid.
Is there an array sort of thing or do I have to make multiple coppies of the script with each numbered one higher then the last?
Dustin Diaz wrote:
Hey there.
This was great. I’ve implemented this on my photo gallery. I’ll leave a special reference to clagnut in the code so expect to see your name appear in some athlete websites.
Daniel wrote:
Hi,
this is an awsome piece of code!! It works flawlessly here. But I hav a problem with the layer where the image is in. I put this layer ontop of some other stuff, and by a click on the image I want to hide the layer again. This works fine as long as I do not fade the image in. Adding the fade feature, I cannot hide the layer anymore. Anybody a glue whats wrong?
Any help greatly appreciated!!
Scott Haefner wrote:
Wow, this is great-I really like it! But it causes content to disappear in Safari 1.2.4.
I was able to reduce the problem to the use of position: relative; in my CSS for content blocks following the image in the HTML (see http://scotthaefner.com/kap/fade-test.html for a very simple example illustrating the problem).
Blocks that use position: relative, and are above the fold do not render (although sometimes they do; most of the time they don’t). You can highlight the text, or scroll the page to get it to render. Obviously, this is unacceptable…anyone got any ideas?
Cheers,
Scott
Daniel wrote:
Hi folks,
just found my issue. He did hide the layer, but for whatever reason not the image itself. Adding a hide to the image did help!
Again, great script!! Thanks!
Christoph wrote:
Hi,
This code is awesome, as was said before. But is there a solution for Opera?
Has someone already added Opera support to this script?
Thx, Christoph
Aaron Swerdlin wrote:
Very nice! I used your stuff as a basis but extended it for multiple photos on the same page and the result is quite nice.
thanks!
mark wrote:
so great.
Can anyone figure out how to incorporate this js into an iframe, or another type of page that loads on the current page, and not a new one?
... to use with multiple images…
thanks.
Dustin Diaz wrote:
By chance, would anyone know how to have an auto-slide-show without using meta refresh or any kind of page refreshing for it to load the new image with the sweet lookin’ fade?
I’m trying to get them to just play automatically without any previous or next buttons.
Alessandro Fulciniti wrote:
Hi Richard, just wanted to let you know that I’ ve written an article (it’s in italian, the set for print version is <a href=”http://pro.html.it/print_articolo.asp/id_558/stampa.html”>here</a>) about this wonderful idea. Here’s the <a href=”http://pro.html.it/esempio/558/DigitalGallery.html”>final example</a>, a unobtrousive gallery with thumbnails and zooms on the same page, combined with the fade effect.
Thanks for sharing.
Fred wrote:
It seems, that you could use a technic as here http://www.paranoidfish.org/boxes/2002/01/14/ to let it works in xhtml. Something like
function ls(){
var cl=d.createElement(‘link’);
cl.setAttribute(‘href’,’js.css’);
cl.setAttribute(‘rel’,’stylesheet’);
cl.setAttribute(‘type’,’text/css’);
document.getElementsByTagName(‘head’).item(0).appendChild(cl);
}
in js.css just
#thephoto{visibility:hidden;}
And also I think, it will be better to call everything this way
function addEvent(obj,evType,fn){
if(obj.addEventListener){
obj.addEventListener(evType,fn,true);
return true;
}
else if(obj.attachEvent){
var r=obj.attachEvent(“on”+evType,fn);
return r;
}
else{
return false;
}
}
addEvent(window,’load’,ls);
addEvent(window,’load’,initImage);
this solution is from here : http://www.sitepoint.com/article/structural-markup-javascript
instead of
window.onload = function() {initImage()}
because it cause error in browsers which are javascript enabled, but not able to do such script (f.e. IE4 and so on)
Thank you anyway for great script
N wrote:
Is it possible without PHP to fade multiple images in a loop without using Flash, and possibly using this setup? I have used my limited knowledge of JS to try and failed miserably…
Andrew Vit wrote:
I’d like to add to this by suggesting a bug workaround for the current version of Safari (1.2.4).
What I found is that when the fading image is CSS-positioned (relative or absolute), the elements that follow aren’t redrawn correctly. Scrolling or resizing the window fixes it, so it’s really just a screen redraw issue.
Essentially, Safari isn’t refreshing elements that are higher in the stacking order (higher z-index) than the fading image. I’ve filed the bug with Apple already, but in the meantime here’s a workaround:
First, set the z-index of your fading div or img to put it “above” your page content (1 is enough if you’re not using z-index anywhere else). This isolates it from interacting with anything that was previously “above” it.
#fading_div { z-index: 1; }
This should typically fix it. If so, stop here.
However, if you have something that needs to overlap your fading image through positioning, you’ll still have the same problem. (But least we’ve now isolated the problem to a single-or a few-elements, instead of all the page content that follows the fader…)
You obviously need to set the overlapping object’s z-index to 2 or greater, to place it higher in the stacking order again.
#overlapper { z-index: 2 }
Then, you need to refresh the overlapping object’s opacity so that it forces a redraw whenever you update your fading image’s opacity, like so:
// add this to the end of setOpacity
bugfix = document.getElementById(‘overlapper’);
bugfix.style.opacity = 99.999;
That ought to do it.
RB wrote:
Thanks, I wrote a flash script a while ago that does something simmilar only fading from 1 image to the other now ive been able to write someting more simple that wont rely on flash and will work with a database driven image page :)
Thomas wrote:
I just wanted to add to the Safari 1.2.4 bug. I had a similar problem with Safari not refreshing a DIV and tried a window.scrollBy(0,0) – which worked!
You can see a demo of this (which should work with most modern browsers) at http://www.fesch.at/projekte/xmlhttptest/test2.html
The demo loads different HTML fragments from the server via xmlhttp (i.e. without having to reload the entire page) and fades them in.
jon wrote:
A couple people have said they can get this to work with xhtml if they use php, but no one has posted a link or code. Would some one out there be kind enough to share with us?
George wrote:
Good work.
I have done something similar and used your code to make a few improvements.
DJims wrote:
Hi !
Nice effect indeed !
I will use it in the photo section of my web site.
Very nice and easy to implement, I mixed it with an autosizing script.
Thanks.
++phil wrote:
nice nice code, as has been said.
for those of you who really love the challenge, i was wondering if there was any way to combine the effects of the onload image fade put together by mr clagnut (see top) and the automatic image slide show at http://slayeroffice.com/code/imageCrossFade/
so that you would have a ‘loading’ work, presumably you could use an animated gif to make it more like flash, that then loaded into the image cross-fading slideshow? all this in just css and javascript… will post any progress i make.
Max wrote:
Sorry – a complete novice question. How do I get it to specify the fade rate depending on what initImage calls? I was trying something along the following InitImage(10), but it will only fade in part way.
function initImage(setfaderate) {
imageId = ‘theimage’;
image = document.getElementById(imageId);
setOpacity(image, 0);
image.style.visibility = “visible”;
fadeIn(imageId,0,setfaderate);
}
function fadeIn(objId,opacity,setfaderate) {
if (document.getElementById) {
obj = document.getElementById(objId);
if (opacity <= 100) {
setOpacity(obj, opacity);
opacity += setfaderate;
window.setTimeout(“fadeIn(‘”+objId+”’,”+opacity+”)”, 100);
}
Bayard Randel wrote:
Excellent script Richard, thank you!
I’ve extended your script a bit to allow for cascading multiple images. Hopefully that will be useful for some people.
http://nocturne.net.nz/webdev/imgfade.php
Kemie wrote:
Thank you for such a great, unobtrusive script. Used it on my site at http://www.monolinea.com/portfolio
anna wrote:
I am a complete novice at JavaScript but have used the slideshow script available at http://javascript.internet.com/miscellaneous/fading-slide-show.html with some success. (The final image fade is mysteriously not smooth like the others)
My question is this: unlike every slideshow I’ve seen, I want mine to STOP on the last image. Any ideas on how to accomplish this?
Steve Deslandes wrote:
Hi, Just to say this is a really great effect. I’ve known about it from your site (and couloir) for some time. One thing to consider is that this works not just for images but for any element on the page.
I’ve been developing a page for a client who required text to fade in on loading and I was doing this by changing the colour with Javascript, however, it’s a much neater way to do it by varying opacity ala your script. I’m sure with a bit of scripting you could develop a script to fade in any piece of text or image you require. This is much better than any of the other javascript based methods I have seen on the web (which all require you to do it using colour) and degrades nicely as there is no flash involved at all.
Rich wrote:
Steve – thanks for that. You make an excellent point that this technique can just as easily be applied to any element on the page.
Chris Chatham wrote:
I am having some trouble getting my “loading.gif” image to display before the main graphic is faded-in. I read that this might be because I lack css, but I do have the style sheet info in a separate file (consulting.css).
I have worked on it for several days and was hoping someone might be able to help me troubleshoot. if so, thanks in advance!
http://www.chatham-consulting.com
rbfigueira wrote:
For me the problem is that I must to wait for the load page complete :
window.onload = function() {initImage()}
Is any possibility to put only when the image is complete loaded ?
More or less like this:
if(this.MyIMAGE.complete){
initImage()
}
The problem is that i want this effect for several images in one simple page ://
Andrew Slayman wrote:
I’m experimenting with this script and very impressed so far. But I’ve come across one problem with setting the opacity to 99.999%: If I print out the page from Mozilla, the image does not print out at all-just whatever’s under it.
I was able to fix this partly by adding two lines at the end of initImage():
obj.style.MozOpacity = 1;
obj.style.opacity = 1;
This prints out okay and doesn’t suffer from the Mozilla flicker, but it does change the fade in another respect: When I hit the refresh button or the back button (to go back to a page with the fade), the image first appears at 100% opacity, then disappears, then fades in. Which is kind of inelegant.
Has anyone else observed this problem and found a solution?
Rich wrote:
Andrew – I don’t know of any other way around the problem you describe, however it is my understanding that the flickering problem that requires the 99.99% opacity has been fixed in Firefox 1.5.
Hodgeman wrote:
Awesome script, I’ve seen it used in the open source gallery project and wanted to use it on a real estate site I’m creating.
http://www.rotoruafirstnational.co.nz
If you browse all listings and click on a listing you get the full details plus all the thumbnails for that listing.
I’m struggling to have just one page with thumbnails which load into a larger div.
I’m changing the src value of the large img to the new image and setting the image visibility to hidden.
Ideally, want I’d like is to have the new image hidden and the background loading.gif show until the new image is fully loaded before fading in.
But at the moment, it’s just showing the last image and just changing to the new image once loaded.
And I don’t know why it’s not working in IE yet….
Any help gratefully appreciated.
Please examine my JS code below.
http://www.rotoruafirstnational.co.nz/js/swapImageScript.js
ira bronson wrote:
Hello. I simply want the background image of a page to fade in. I have tried other js methods but are interfering with my dynamic scrolling. I simply want the page’s background image to fade in when the page loads.
Thank you.
Tin wrote:
there still seems to be no support for Opera. is there a quick fix for this? thank you so much.
Tin wrote:
actually it’s Opera at fault. apparently Opera currently does not support opacity effects through its javascript.
latenate wrote:
Thank you, this is brilliant! Tried modifying it to allow someone to fade-slideshow through a gallery by clicking on each image… unfortunately, if you click too quickly, things get gummed up. This happens even after I set a flag to stop the previous fade and start a new one…
I think my image preloaders are working and intact, although they aren’t quite behaving that way! Thanks again, for setting my brain afire.
g’night all
Alex Kadis wrote:
Thank you!
I used it on my site: http://portfolio.kadisdesign.com/
Peter Kytlica (Slovakia) wrote:
Very usefully!
I just smile about the phrase: “I’ve deliberately made the image quite a large filesize so you’ll have a chance to see…” , but you doing that with 207kB jpg, so for me it is not chance to see ‘loading’ if I have T1 (about 5MB per second.) ...lol
...pixo
Simon Willison wrote:
Natalie Downe has a really cool permalink slideshow demo which fades between slides, lets you link to slides within the page and degrades gracefully to boot :)