By Craig Buckler

How to Create a CSS3 Ajax Loading Icon Without Images

By Craig Buckler

There’s an inevitable delay whenever your web application interacts with the server. That could be for an Ajax request, uploading a file, or using newer HTML5 APIs such as web sockets or server-sent events.

Ideally, you should give the user some feedback to indicate their action is being processed. You’ll often see small animated GIFs with rotating patterns. There are several sites which will create them for you, such as and

Images are the best cross-browser option but they have a number of issues:

  • GIFs do not support alpha-transparency. You need to be careful when placing the image on a colored background.
  • Bitmap images won’t scale nicely. If you change the dimensions, you need to create a new image.
  • If you’re not careful, animated graphics can have a large file size.
  • Images incur an additional HTTP request. While the image will be cached, the initial download may take longer than the background process it represents! You can code around this issue by pre-loading the image or using embedded data URLs but it’s more effort.

Fortunately, CSS3 allows us to create loading icons without images. They’re easy to create, scale, re-color, use on any background and don’t incur image downloads. You require:

  1. A single HTML element, e.g. <div id="ajaxloader"></div>.
  2. A few CSS backgrounds, border and shading effects to create a graphical icon.
  3. CSS3 transformations and animations to rotate or move the element.

View the demonstration page…

Browser Compatibility

CSS3 transformations and animations are experimental properties which require vendor prefixes — and you know what trouble they cause. The example code implements the final property as well as prefixes for -webkit (Chrome and Safari), -moz (Firefox), -ms (IE), and -o (Opera), but there’s no guarantee they’ll work consistently if at all.

At the time of writing, recent versions of Chrome, Safari and Firefox offer CSS3 animations. IE9/8/7/6 and Opera show a static image, although IE10 and Opera 12 may support the properties.

Just to complicate matters further, Firefox allows you to animate pseudo elements separately. You can therefore add a couple of elements using :before and :after and rotate or move them in different directions to create more complex animations. While I’d initially hoped to do that, it doesn’t work in the webkit browsers. Chrome and Safari only allow real elements to be animated. It appears to be a bug or oversight, but it’s not been fixed in the current or beta releases.

Creating the Icon

Our HTML div can be placed anywhere in the document although it might be best to append it as the last child of the body. It will then appear above other elements and can be positioned in relation to the page.

The icon CSS simply sets wide white rounded border. The right border color is then set to transparent and a little shading is applied:

	position: absolute;
	width: 30px;
	height: 30px;
	border: 8px solid #fff;
	border-right-color: transparent;
	border-radius: 50%;
	box-shadow: 0 0 25px 2px #eee;

The result:

CSS Ajax icon 1

It’s easy to tweak the properties for different effects, e.g. adding border-right: 0 none; produces:

CSS Ajax icon 2

Animating the Icon

To make the icon spin and pulsate, we apply rotation transformations and opacity changes within a CSS3 animation. The animation name, duration, easing type and repeat are applied to the element:

	animation: spin 1s linear infinite;

followed by the animation keyframes:

@keyframes spin
	from { transform: rotate(0deg);   opacity: 0.2; }
	50%  { transform: rotate(180deg); opacity: 1.0; }
	to   { transform: rotate(360deg); opacity: 0.2; }

None of the browsers support animation without vendor prefixes so you’ll see -webkit, -moz, -ms and -o alternatives within the source code when you view the demonstration page.

The icon can now be displayed using a little JavaScript whenever an Ajax request is initiated. It’s a great effect which can be customized easily and works on 55% of current browsers.

Unfortunately, 45% of web users won’t see the animation. That number will fall when IE10 is released and users switch to recent versions of other browsers, but it remains a large percentage. You could fall back to an image but, if you’re doing that, you might as well use the image for all browsers.

I therefore suggest you look at your own statistics. If your visitors are are predominately using Chrome, Safari and Firefox you could adopt the technique today. If not, stick with images for now and wait a little longer for more consistent browser support.

  • Great Work Guys :)

  • sean

    very nice. In past i’ve used spin.js (

  • If the only cross-browser problem is animation you can animate the transformations using javascript, to make it work in more browsers, while still not using images. Or am I missing something?

    • You still can’t (easily) do transformations in JavaScript unless you resort to something like SVG. But that would mean you’re using an image anyway.

  • David

    Why is it that Sitepoint articles keep referring to the http request overhead incurred by a couple of extra images? While I had to wait 30 (yes, 30) seconds for the images in your ‘Buy Our CSS book’ lightbox to load so I could then find and then click on the Close button and make this comment?

  • In the latest version of Chrome, I’m getting static icons and then the demonstration page locks up…

    • That sounds strange and I can’t reproduce the problem. It might be worth reinstalling.

  • James W

    Good idea, I simplified the appearance a bit is a good backup though – it generates animated GIFs

  • Ian


    I read this article about a week ago and it set me wondering. I had to ponder for some time beofre posting here… but here goes.

    I can’t help but think you’re solving a problem that does not exist, or even providing a solution that is worse than the problem.

    Animated gifs have been around for so long now they’re universally supported, the’res a gajillion examples around, and they’re dead simple to implement. Implementing an in-progress indicator should be a no-brainer, not only for the developers setting up the application but the guys that need to support that same application in the future.

    Doing it via CSS3 is no doubt nifty and clever, and apart from a very small data payload benefit but doesn’t give a real improvement when solving the original problem. In fact in some ways it makes it worse, we’ve seen here it introduces uncertainty associated with browser compatbilities.

    The other big-time rule it breaks is that of affordance. Everyone knows what an in-progress indicator looks like, right? It’s a silver, whirly spoked wheel, or a slidey progress bar with a coloured insert. Changing it to something else breaks this affordance and risks confusing the most basic visitors to your site. It may be only a momentary confusion, but (IMO) it breaks the basics of the rules set out in “Don’t Make Me Think”.

    I appreciate this post as a demonstration of the things that can be done with CSS3 and for that it’s a good programming exercise and skill, but if one of the guys on my team implemented an in-progress indicator in this manner or one that looked different to what we’re all used to, I’d ask them to fix it, to bring back the affordance and maintainabilty.

    My intent in this response is not to criticise the author, yet I seem to do so. I found it interesting, but I would not advocate the use of this technique in a real work web set. At least not yet.


    • Thanks Ian. I generally agree with you — we’re not at a point where animated GIFs are redundant. It’s a technique to keep an eye on rather than adopt now. However, CSS3 effects are easier to create, scalable, can be used on any background, offer an instant response and save bandwidth. Those are big advantages.

      Finally, is there a standard progress indicator style? I doubt users would be confused by the examples I created — especially because they could be huge or even follow the cursor!

  • Oh…Great man !Thanx a ton for this post ! i was searching that easy method from along time..

Get the latest in Front-end, once a week, for free.