Preloading images via CSS

What’s the difference between these 2, and should it be,

before:

or

after:

Is having it one way better than the other?

Is one way more right than the other?

What’s happening here?

.image:after {
  content: "";
  background: url(https://i.imgur.com/AJDZEOX.jpg), url(https://i.imgur.com/UzRn6Qx.png), url(https://i.imgur.com/96Q10GA.png), url(https://i.imgur.com/WzHsnG7.png), url(https://i.imgur.com/CzqEXBq.jpg), url(https://i.imgur.com/fOfpsiC.png), url(https://i.imgur.com/b3Rqi4d.png);
  width: 0;
  height: 0;
  visibility: hidden;
}

What’s happening here?

.image:after {
  content: "";
  background: url(https://i.imgur.com/AJDZEOX.jpg), url(https://i.imgur.com/UzRn6Qx.png), url(https://i.imgur.com/96Q10GA.png), url(https://i.imgur.com/WzHsnG7.png), url(https://i.imgur.com/CzqEXBq.jpg), url(https://i.imgur.com/fOfpsiC.png), url(https://i.imgur.com/b3Rqi4d.png);
  width: 0;
  height: 0;
  visibility: hidden;
}

Also:
Is doing it this way bad?
https://jsfiddle.net/g72cho6j/85/

  <div class="hide">
  <img src="https://i.imgur.com/AJDZEOX.jpg" alt="" />
  <img src="https://i.imgur.com/UzRn6Qx.png" alt="" />
  <img src="https://i.imgur.com/96Q10GA.png" alt="" />
  <img src="https://i.imgur.com/WzHsnG7.png" alt="" />
  <img src="https://i.imgur.com/CzqEXBq.jpg" alt="" />
  <img src="https://i.imgur.com/fOfpsiC.png" alt="" />
  <img src="https://i.imgur.com/b3Rqi4d.png" alt="" />
  </div>

.hide {
  display: none;
}

I keep seeing them written with either:

visibility: hidden;

or

display: none;

I’ve even seen one written using both:

display: none;
visibility: hidden;

Is one better than the other, or even using both?

I know all these I’ve listed work in firefox, but I don’t know about other browsers.

This one uses this:
https://jsfiddle.net/g72cho6j/97/

<div class="image">
  <img src="https://i.imgur.com/AJDZEOX.jpg" alt="" />
  <img src="https://i.imgur.com/UzRn6Qx.png" alt="" />
  <img src="https://i.imgur.com/96Q10GA.png" alt="" />
  <img src="https://i.imgur.com/WzHsnG7.png" alt="" />
  <img src="https://i.imgur.com/CzqEXBq.jpg" alt="" />
  <img src="https://i.imgur.com/fOfpsiC.png" alt="" />
  <img src="https://i.imgur.com/b3Rqi4d.png" alt="" />
</div>

.image img {
  visibility: hidden;
  position: absolute;
}

If the image is display:none (or possibly visibility:hidden or width:0 and height:0) some browsers are clever enough to know that he image is hidden and therefore will not download it until it is needed on the page. Therefore the best method is to place the image offscreen (e.g. position:absolute; left:-999em;top:-999em) and not use display:none or visibility:hidden.

Don’t add extra elements to preload images anyway as you can use body:after (or:before) to do that. Of course preloading images may slow your initial page down if you are loading images that are not needed until later and a js method would be better.

1 Like

I’ll stick with the javascript one then.

This way works good I found:

Does anyone know why it works really well?

Not a lot of code, simple to use, and does what it’s supposed to do.

  <script>
  if (document.images) {
    img1 = new Image();
    img1.src = "https://i.imgur.com/AJDZEOX.jpg";
    img2 = new Image();
    img2.src = "https://i.imgur.com/UzRn6Qx.png";
    img3 = new Image();
    img3.src = "https://i.imgur.com/96Q10GA.png";
    img4 = new Image();
    img4.src = "https://i.imgur.com/WzHsnG7.png";
    img5 = new Image();
    img5.src = "https://i.imgur.com/CzqEXBq.jpg";
    img6 = new Image();
    img6.src = "https://i.imgur.com/fOfpsiC.png";
    img7 = new Image();
    img7src = "https://i.imgur.com/b3Rqi4d.png";
  }
</script>

What if it’s, display:none with
width:1 and height:1 ?

IF it’s display none then the size is irrelevant as the image is not there anhyway. As I said before some browsers ‘may’ decide not to downliad the image if it isn’t yet required.

1 Like

Will either of these ways work as you had suggested?

Is one way preferred over the other?

Wait, there’s no position:absolute; left: on these.

Can you show me an example of how it would be set up?

But what if the images are in the CSS, not the html?

This is the code:

These are my images

https://i.imgur.com/fOfpsiC.png
https://i.imgur.com/92kMrMf.jpg
https://i.imgur.com/WzHsnG7.png
https://i.imgur.com/96Q10GA.png
https://i.imgur.com/UzRn6Qx.png
https://i.imgur.com/1TbGgqz.png
https://i.imgur.com/AJDZEOX.jpg

Code 1

.preload-images {
	background: url(image-01.png) no-repeat -9999px -9999px;
	background: url(image-01.png) no-repeat -9999px -9999px,
		    url(image-02.png) no-repeat -9999px -9999px,
		    url(image-03.png) no-repeat -9999px -9999px,
		    url(image-04.png) no-repeat -9999px -9999px,
		    url(image-05.png) no-repeat -9999px -9999px;
	}

Code 2

.preload-01 { background: url(image-01.png) no-repeat -9999px -9999px; }  
.preload-02 { background: url(image-02.png) no-repeat -9999px -9999px; }  
.preload-03 { background: url(image-03.png) no-repeat -9999px -9999px; }
.preload-04 { background: url(image-04.png) no-repeat -9999px -9999px; }
.preload-05 { background: url(image-05.png) no-repeat -9999px -9999px; }

If these are all considered background images:
Because they are all inside the CSS,

How would your method work with images that only appear in the CSS?

https://i.imgur.com/fOfpsiC.png
https://i.imgur.com/92kMrMf.jpg
https://i.imgur.com/WzHsnG7.png
https://i.imgur.com/96Q10GA.png
https://i.imgur.com/UzRn6Qx.png
https://i.imgur.com/1TbGgqz.png
https://i.imgur.com/AJDZEOX.jpg

Just add then to body:after{} all in one go.

e.g.


body:after{
	content:"";
	position:absolute;
	left:-999em;
	top:-999em;
	z-index:-1;
	background: url(image-01.png) no-repeat 0 0,
		    url(image-02.png) no-repeat 0 0,
		    url(image-03.png) no-repeat 0 0,
		    url(image-04.png) no-repeat 0 0,
		    url(image-05.png) no-repeat 0 0;
}
1 Like

What’s the purpose of z-index here?

z-index - 1 included

body:after {
  content: "";
  position: absolute;
  left: -999em;
  top: -999em;
  z-index: -1;
}

z-index removed:


body:after {
  content: "";
  position: absolute;
  left: -999em;
  top: -999em;

Just to make sure its out of the way and under anything else. It’s not really necessary but who knows you might upload a massive image that is bigger than 999em squared :slight_smile:

Is 999em the same as -9999px ?

No :slight_smile:

One is px and one is em :slight_smile:

999em will equate to 999 times the default font-size (which is usually 16px unless the user has changed it). It means that if font-size is increased the element moves further out of the way as a result and much safer to use.

1 Like

999em is equivalent to what in width / height?
16 x 999 = 15984

15984 x 15984

Only if the font-size is set to 16px.

If I have poor eyesight and set my default font to 20px or 24px or whatever, 999em will be correspondingly larger on my screen.

The whole point of using ems is that they are flexible; don’t try to convert them to pixels.

3 Likes

Why body.after, ?

body:after {
  content: "";
  position: absolute;
  left: -999em;
  top: -999em;
  z-index: -1;
}

How come ‘before’ wasn’t used instead?

body:before{
  content: "";
  position: absolute;
  left: -999em;
  top: -999em;
  z-index: -1;
}

Why? What additional benefits does it provide?

What does it do differently to the method I chose?

Answer: None

There is no real difference between the two choices in this case so use one or the other. It doesn’t matter which except that historically :after had better support but that is irrelevant these days in modern browsers.

This doesn’t directly answer your question but really this should be done using HTTP 2.0. Ideally via HTTP headers but you can also do it with link tags:

<link rel="preload" href="https://i.imgur.com/AJDZEOX.jpg" as="image">
1 Like

How would I be able to incorporate this with how you set up the above code?

The javascript part, how would I be able to link that, with the CSS part?

#preload-01 { background: url(http://domain.tld/image-01.png) no-repeat -9999px -9999px; }
#preload-02 { background: url(http://domain.tld/image-02.png) no-repeat -9999px -9999px; }
#preload-03 { background: url(http://domain.tld/image-03.png) no-repeat -9999px -9999px; }

As effective as this method is, however, there is room for improvement. As Ian points out, images that are preloaded using this method will be loaded along with the other page contents, thereby increasing overall loading time for the page. To resolve this issue, we can use a little bit of JavaScript to delay the preloading until after the page has finished loading.

function preloader() {
	if (document.getElementById) {
		document.getElementById("preload-01").style.background = "url(http://domain.tld/image-01.png) no-repeat -9999px -9999px";
		document.getElementById("preload-02").style.background = "url(http://domain.tld/image-02.png) no-repeat -9999px -9999px";
		document.getElementById("preload-03").style.background = "url(http://domain.tld/image-03.png) no-repeat -9999px -9999px";
	}
}
function addLoadEvent(func) {
	const oldonload = window.onload;
	if (typeof window.onload != 'function') {
		window.onload = func;
	} else {
		window.onload = function() {
			if (oldonload) {
				oldonload();
			}
			func();
		}
	}
}
addLoadEvent(preloader);

How would I be able to connect the CSS with the javascript?

CSS

body:after {
  content: "";
  position: absolute;
  left: -999em;
  top: -999em;
  z-index: -1;
  background: url(https://i.imgur.com/fOfpsiC.png) no-repeat 0 0, url(https://i.imgur.com/92kMrMf.jpg) no-repeat 0 0, url(https://i.imgur.com/WzHsnG7.png) no-repeat 0 0;
}

This is the only part that isn’t set up because I’m confused how these will be connected.

There’s no id in the CSS part: Only body and after.

body:after {

javascript

function preloader() {
	if (document.getElementById) {
		document.getElementById("preload-01").style.background = "url(http://domain.tld/image-01.png) no-repeat -9999px -9999px";
		document.getElementById("preload-02").style.background = "url(http://domain.tld/image-02.png) no-repeat -9999px -9999px";
		document.getElementById("preload-03").style.background = "url(http://domain.tld/image-03.png) no-repeat -9999px -9999px";
	}
}
function addLoadEvent(func) {
	const oldonload = window.onload;
	if (typeof window.onload != 'function') {
		window.onload = func;
	} else {
		window.onload = function() {
			if (oldonload) {
				oldonload();
			}
			func();
		}
	}
}
addLoadEvent(preloader);

Writing them individually the CSS would look like this:

body:after {
  content: "";
  position: absolute;
  left: -999em;
  top: -999em;
  z-index: -1;
  background: url(https://i.imgur.com/fOfpsiC.png) no-repeat 0 0;
}

body:after {
  content: "";
  position: absolute;
  left: -999em;
  top: -999em;
  z-index: -1;
  background: url(https://i.imgur.com/92kMrMf.jpg) no-repeat 0 0;
}

body:after {
  content: "";
  position: absolute;
  left: -999em;
  top: -999em;
  z-index: -1;
  background: url(https://i.imgur.com/WzHsnG7.png) no-repeat 0 0;
}

I’m not sure why you’re trying to follow a nine-year-old tutorial, when you’ve been advised against using old resources, but if that’s what you want to do, then follow the tutorial. Read the instructions and do what they tell you to do.

In the first part of this script, we are setting up the actual preloading by targeting specific preload elements with background styles that call the various images. Thus, to use this method, you will need to replace the “ preload-01 ”, “ preload-02 ”, “ preload-03 ”, etc., with the IDs that you will be targeting in your markup.

So, find each HTML element you want to apply a background to and give it an ID. You can call them “ preload-01 ”, “ preload-02 ”, etc., if you want, or you can give them more descriptive IDs and change the script to match.

1 Like