Lumenaki Crystal Loader
TL;DR;
See the Pen Lumenaki Loader by Khanh Hua (@khanhhua) on CodePen.
Long Story
Skills involved
-
CSS3 animation
-
CSS3 transform
-
Basic geometry and math
-
Patience
How to build
The HTML structure
.loader
.quadrant
.quadrant-sub
span
.quadrant-sub
span
.quadrant
.quadrant-sub
span
.quadrant-sub
span
.quadrant
.quadrant-sub
span
.quadrant-sub
span
.quadrant
.quadrant-sub
span
.quadrant-sub
span
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 for the piece of code in production.