I was buying a book for my daughter over PayPal earlier today. As my money was being sped away from me over the intertubes, I was presented with a loading indicator, known in the web dev trade as a spinner. I liked that spinner. I wanted to know how they did it.

This is what the spinner looked like:

See the Pen PayPal’s loading spinner by Paul (@peiche) on CodePen.0

I didn’t have to wait long for PayPal to finish processing my payment for my daughter’s book, so I wasn’t given enough time to fire up Chrome’s element inspector to find the element or class. I didn’t think it would be too difficult to reverse-engineer it, however.

With semantic CSS classes, it’s common to give a loading indicator a name like .spinner or .loading. As it turned out, a quick search through PayPal’s core stylesheet revealed it was both (I’ve stripped out the vendor-prefixed properties for brevity’s sake):

.spinner.loading {
  padding-top: 5em;
  margin-top: 8em;
  position: relative;
  text-align: center;
  font-size: 1.5em

.spinner.loading:before {
  content: "";
  height: 30px;
  width: 30px;
  margin: -15px auto auto -15px;
  position: absolute;
  top: 50%;
  left: 50%;
  z-index: 6;
  border-width: 8px;
  border-style: solid;
  border-color: #2180c0 rgba(0,0,0,0.2) rgba(0,0,0,0.2);
  animation: rotation .7s infinite linear;
  border-radius: 100%;

Simple enough, actually. They’re just using a one-siding border technique — not too different from how tooltip triangles are made — and then rounded and animated. If you take away the animation and border-radius properties, you’re left with this:

See the Pen PayPal’s loading spinner, sans animation and border-radius by Paul (@peiche) on CodePen.0

It’s much more evident what the element actually is, now. Adding this will make the element round again:

border-radius: 100%;

But there’s still the matter of making it spin. The animation property references rotation — that would be the keyframes that define the animation states. A simple search through PayPal’s stylesheet for “@keyframes rotation” reveals this:

@keyframes rotation {
  from {
    transform: rotate(0deg);
  } to {
    transform: rotate(359deg);

And here you can see the progression from what looks like no more than a box, to a circle, to a spinning loading animation. It’s concise, imageless, and resolution independent, just like an HTML5 app should be.

See the Pen PayPal’s loading spinner, progressively enhanced by Paul (@peiche) on CodePen.0

Husband. Daddy. Programmer. Artist. I'm not an expert, I just play one in real life.
  • Will Howard

    This is great! I was just thinking about how beautifully simple the PayPal spinner is and you’ve helped me to replicate it in my own web app :)