The new SVG HipChat loading screen - faster without React

March 17th 2015 Dave Elkan in React, Css, Svg, Hipchat, JavaScript

We love gifs on the HipChat team. We love them so much that we were temporarily misled by their sirens' call. Here's how we plugged our ears and continued on to the fabled land of SVG, optimizing our loading screen and reducing its size by 95%.

Fatty the gif and the loading screen

Our original loading screen was a thing of beauty. A pure white screen sporting an animated, retina HipChat logo rolling over its tail into the future and beyond.

A hidden, pre-loader HipChat loading gif The old HipChat loading gif
Roll over to animate

This retina gif's size (a chunky 53KB) was the source of its demise. It was simply too big for a loading screen, often arriving late and missing the party entirely.

Size aside, the old loading screen was a part of the greater web app. This meant it would not appear until React and all of the other dependencies of the web client were loaded. That sounds counter-intuitive, but when we first launched the beta, the javascript payload was smaller. The loading screen was simply used to hide the UI whilst we fetched the initial HipChat session data. Since then we've added countless features, like inline file previews, increasing the download size.

We've gone one better. The loading screen now loads before React. Infact, the SVG HipChat logo and animation CSS are inline in the HTML, so there's no additional requests to make to show the loading screen.

Captivating new users

New users are precious and first impressions last. If you have to keep them waiting, captivate them. Quickly.

After our initial web client beta release, we conducted an intense study of the new user on-boarding flow. It was then that we discovered our gif issue. In production, new users with an empty cache on a typical internet connection, often didn't see our fancy loading gif at all.

Farewell gif. Hello SVG.

Our new web client already uses SVG symbol definitions for our status icons, so it was a no-brainer to add a HipChat logo along-side them.

With this HTML and CSS:

<svg height="0" style="display:block;" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
  <symbol id="icon-hipchat-logo" viewBox="0 0 1024 1024">
    <title>hipchat-logo</title>
    <path class="path1" d="M791.552 ..."></path>
    <path class="path2" d="M932.864 ..."></path>
  </symbol>
</svg>
#icon-hipchat-logo .path1, #icon-hipchat-logo .path2 {
  fill: #205081;
}

It looks a little like this:

Let's dance!

Advanced CSS animations are tricky. The animation loop needed to account for the logo's tail striking the ground. Piecing something intricate like this together with the provided transition types (ease-in, ease-out, etc) is a great recipe for a self-induced lobotomy. Instead, thanks to Joel Unger on the design team, I was able to create rotation and translation keyframe rules from the original After Effects timeline.

Original After Effects keyframes

The loop is 49 frames at 29.97fps giving us a total length of 0.6 seconds. From here we can create percentage-based keyframes. i.e. At frame 22 (46% through the loop), when the tail hits the ground, we want to apply a rotation of 20 degrees and translation of 7 pixels up.

*Please note this snippet does not include browser-prefixes currently required to work in all browsers.

.loading-message .loading-outer {
  animation: translationFrames linear 0.66s infinite;
  transform-origin: 50% 50%;
}

.loading-message .loading-inner {
  animation: rotationFrames linear 0.66s infinite;
  transform-origin: 50% 50%;
}

@keyframes translationFrames {
  42% {
    transform: translate(0, -7px);
  }
}

@keyframes rotationFrames {
  42% {
    transform: rotate(20deg);
  }
}

The result

From a 53KB gif to 1.8KB of HTML and CSS (both sizes gzipped).

Roll over to animate

You can find all of the code for this CSS animation by viewing the source of this blog post (or by signing up for a HipChat account).