Innovation rarely happens in a vacuum. It usually starts with an individual brave enough to contribute an idea and a team inspired enough to make it great. This blog provides a forum for all Centrons to contribute ideas, make suggestions, ask questions and inspire others. There are no boundaries. To participate, all you need is the desire to build great products.

Build a Loading Animation with CSS and React

Recently, the Centro team realized that the data-heavy parts of our application were not loading immediately. Because we didn’t want users to think something was wrong, we decided to employ a familiar pattern and add a loading animation to the app:

CSS Loading Animation

We needed the animation to be flexible, as it would be used full-screen and in variable-sized containers. Our preference was for a code-based solution (instead of a static asset like an image) so we could maintain a finer level of control over behavior and usage.

Our application uses React and its animation library so we started by creating a custom component. Below we use our default h1 styling then add some span tags around the word “Loading” and each period after it:

module.exports = React.createClass({
  render: function() {
    return (
      <div>
        <span className="Loader">
          <div className="Loader-indicator" >
            <h1>
              <span>Loading</span>
              <span className="Loader-ellipsis" >
                <span className="Loader-ellipsisDot">.</span>
                <span className="Loader-ellipsisDot">.</span>
                <span className="Loader-ellipsisDot">.</span>
              </span>
            </h1>
          </div>
        </span>
      </div>
    );
  }
});

The React animation library applies classes to elements when they are added or removed from the DOM, so we tell our loader component how to behave when it enters and leaves:

.Loader-indicator.fade-enter,
.Loader-content.fade-enter {
  opacity: 0;
}

.Loader-indicator.fade-enter-active,
.Loader-content.fade-enter-active {
  opacity: 1;
}

.Loader-indicator.fade-leave,
.Loader-content.fade-leave {
  opacity: 1;
}

.Loader-indicator.fade-leave-active,
.Loader-content.fade-leave-active {
  opacity: 0;
}

.Loader-content,
.Loader-indicator {
  transition: opacity 1s;
}

Then we style our dots by adding some animation instructions for duration, count and timing. We want linear timing in this case for steady, even pacing from the beginning-to-end:

.Loader-ellipsisDot {
  padding: 0 3px 0 1px;
  opacity: 0;
  animation-duration: 3000ms;
  animation-iteration-count: infinite;
  animation-timing-function: linear;
}

Now we create animation keyframes that tell each of our dots how to behave at certain points in the animation:

@keyframes Loader-ellipsisDot1 {
  0%   { opacity: 0; }
  25%  { opacity: 0; }
  35%  { opacity: 1; }
  100% { opacity: 1; }
}

In the case of our first ellipses dot, it will be invisible from 0–25% of the timeline, transitioning to visible from 25%–35%, and then remaining visible until the end. From here it will start over because we chose a count of infinite.

We do the same for the other two but sequentially stagger the timing. The second dot will start its transition at 50%, and the third at 75%. Notice how the same amount of timeline (10%) is used between the second and third keyframes so the dots fade in consistently:

@keyframes Loader-ellipsisDot2 {
  0%   { opacity: 0; }
  50%  { opacity: 0; }
  60%  { opacity: 1; }
  100% { opacity: 1; }
}

@keyframes Loader-ellipsisDot3 {
  0%   { opacity: 0; }
  75%  { opacity: 0; }
  85%  { opacity: 1; }
  100% { opacity: 1; }
}

Lastly, we assign these keyframes to each dot with the :nth-child(n) selector:

.Loader-ellipsisDot:nth-child(1) {
  animation-name: Loader-ellipsisDot1;
}

.Loader-ellipsisDot:nth-child(2) {
  animation-name: Loader-ellipsisDot2;
}

.Loader-ellipsisDot:nth-child(3) {
  animation-name: Loader-ellipsisDot3;
}

And there you have it: a React-based, text-only, loading screen animated sequentially with CSS.