Lumenaki Crystal Loader

#TL;DR;

<p data-height="297" data-theme-id="0" data-slug-hash="WQwwdL" data-default-tab="result" data-user="khanhhua" class='codepen'>See the Pen <a href='http://codepen.io/khanhhua/pen/WQwwdL/'>Lumenaki Loader</a> by Khanh Hua (<a href='http://codepen.io/khanhhua'>@khanhhua</a>) on <a href='http://codepen.io'>CodePen</a>.</p>

<script async src="//assets.codepen.io/assets/embed/ei.js"></script>

#Long Story

##Skills involved

- CSS3 animation

- CSS3 transform

- Basic geometry and math

- Patience

##How to build

###The HTML structure

   .loader

     .quadrant

       .quadrant-sub

         span &nbsp;

       .quadrant-sub

         span &nbsp;

     .quadrant

       .quadrant-sub

         span &nbsp;

       .quadrant-sub

         span &nbsp;

     .quadrant

       .quadrant-sub

         span &nbsp;

       .quadrant-sub

         span &nbsp;

     .quadrant

       .quadrant-sub

         span &nbsp;

       .quadrant-sub

         span &nbsp;

You may want to use `.quadrant-sub:after` to create pseudo elements instead of `span`. Anyways, let us analyze the structure. As you have observed:

- The indicator rotates about its center

- The diamonds rotate about 2 axes: one diagonal and its center

- Each diamond has two separate sub-parts, only one of the two is visible at a time.

There is a reason behind the aforementioned structure. We will discuss after we explore the CSS declarations.

###CSS

The most interesting aspect would be keyframe definitions for rotations. Each DOM (loader, quadrant and subpart) needs to associate with one and only animation, one and only one transformation.

- The loader (`.loader`)

```

   @keyframes ani-loader {

     0% {

       transform: rotate(0deg);

     }

     69% {

       transform: rotate(0deg);

     }

     100% {

       transform: rotate(90deg);

     }

   }

```

- The sub-parts (`.quadrant-sub`)

```

   @keyframes ani-quad1-ne {

     0% {

       transform: rotate3d(-1,1,0,0deg);

     }

     20% {

       transform: rotate3d(-1,1,0,0deg);

     }

     44% {

       transform: rotate3d(-1,1,0,90deg);

     }

     100% {

       transform: rotate3d(-1,1,0,90deg);

     }

   }

   @keyframes ani-quad1-nw {

     0% {

       transform: rotate3d(1,1,0,90deg);

     }

     44% {

       transform: rotate3d(1,1,0,90deg);

     }

     55% {

       transform: rotate3d(1,1,0,0deg);

     }

     100% {

       transform: rotate3d(1,1,0,0deg);

     }

   }

```

- The quadrants (`.quadrant`)

```

   @keyframes ani-quad1-rotate {

     0% {

       transform: rotate(0deg);

     }

     52% {

       transform: rotate(0deg);

     }

     69% {

       transform: rotate(90deg);

     }

     100% {

       transform: rotate(90deg);

     }

   }

```

I have shown this crystal loader to a few interviewees and colleagues. Most of them assumed an over simplistic solution in terms of both CSS and HTML structure. The common mistake is how the animated property `transform` is understood. In my solution, there are 13 `keyframes` definitions while the often proposed figure is 4. To animate this loader, we need:

- 1 `keyframes` definition for the entire block

- 4 `keyframes` definitions for the `.quadrant`

- 8 `keyframes` definitions for the `.quadrant-sub`

The take-away point is that CSS matrix transformation is basically an application of **linear** algebra. By **linear**, it means each point of our DOM elements is converted from its original position to the final destination. No matter how many `translate`, `rotate`, `scale` and `skew` you may apply for the transform property, browser will calculate one and only one `matrix` which represents the entire transformation. During animation/transition, the final destination is recalculated based on the original position - NOT the previously calculated value using this `matrix`.

Put that altogether, we now understand how this loader works:

- To produce the diamond, one `matrix` is used for the `  .quadrant-sub span`s.

- To make the diamond flip around the diagonal, one `matrix`* is applied for `.quadrant-sub`.

- To make the diamond rotate around its center, one `matrix`* is applied for the `.quadrant`s. Their children are rotated also.

- To make the whole block rotate, one `matrix`* is applied for the `.loader`.

*`matrix` value is an interpolated figure.

In other words, you *cannot* make **the diamonds, by themselves, distorted and animated at the same time**. You have to wrap them as many levels as the number of concurrent `matrix` values are used.

#Your assignment

Can you make this Lumenaki Crystal Loader adapt to various sizes? How about making the loader fluid?

See [Lumenaki - album 209](http://www.lumenaki.com/albums/209) for the piece of code in production.

Lumenaki Crystal Loader
Share this