In this article we continue our CSS 3 deconstruction of how Julian Garnier’s 3D Solar System was built. This time, we’ll rotate the entire solar system 3-dimensionally so that the planet orbits become elliptical and the planets actually move behind the sun.

In our deconstruction of the CSS 3 of Julian Garnier’s fantastic solar system animation, we had managed to have a single planet rotate smoothly around the sun using CSS keyframe animation, with the sun throwing dynamic shadows onto the planet surface. However, our orbits are perfectly round and the magic of Julian’s solar system animation is that the planets move in elliptical orbits, and, more importantly, that they are hidden when they pass behind the sun.

(If you’ve landed here from somewhere, you can go to the beginning of this tutorial on Deconstructing CSS: Making of the CSS 3 Solar System.)

Here’s what we have so far:

See the pen on CodePen.

Rotating the solar system

We have now come to a point were we can unleash the true power of CSS 3 and perform an amazing trick: we are going to rotate the entire solar system around its X-axis (the horizontal axis passing from left to right through your screen), so that our orbits are turned into ellipses. As it turns out, CSS 3 actually supports transformations in three-dimensional space, so we can do it all in one instruction:

#galaxy {
  ...
  transform: rotateX(75deg);
}

Our whole solar system is now rotated backwards, so we are looking at it from on angle! In fact, rotating the galaxy <div> has rotated all of its contents, so our sun and planets are now also discs floating through space. In fact, all <divs> that we specify and format really are 2-dimensional objects, so it makes sense that CSS does what it does. We’ll now need to jump through a couple of hoops to get things right.

First things first – the sun must be rotated back so that we see it full-on again:

#sun {
  ...
  transform: rotateX(-75deg);
}

Hmm. That didn’t work. The sun has rotated 75 degrees, but within the already rotated galaxy, and remains flattened. What we need is for the sun not to inherit the galaxy’s rotation, but have only a rotation of its own. We can do that by adding the transform-style property to galaxy, giving is a value of preserve-3d:

#galaxy {
  ...
  transform-style: preserve-3d;
  transform: rotateX(75deg);
}

That fixes it; the sun is now round again while the orbit remains elliptical. But wait, something awesome has just happened! Look closely and you’ll see that the planet is not actually passing behind the sun! It turns out that when you rotate a group of elements using CSS transformations, CSS 3 automatically adjust z-indices based on position.

See the pen on CodePen.

Rotating the planets back to their original angles

The preserve-3d CSS value may have saved our sun, but it doesn’t work for the planets. That’s because the angle of the planets toward the screen constantly changes, because they’re part of the rotating orbit animation. Getting the planets to face the screen can be done by creating a new animation that counteracts the rotations imposed by the orbit animation.

First, we’ll place our planets inside a special div with class pos. This has three benefits:

  • The planets already have their own shading animation. No element can have multiple animations, so by wrapping each planet in another element we can add the animation we need to counteract the orbit rotation;
  • If we decide to add labels to the planets (like Julian Garnier’s CSS 3 solar system animation has), we’ll need an element that groups the planets with their labels;
  • We can use the .pos element to draw a square around our planets to see how they’re actually rotating.

So, our HTML changes to:

<div id="mercury" class="orbit">
  <div class="pos">
    <div class="planet"></div>
  </div>
</div>

We add the following CSS:

.pos {
  position: absolute;
  width: 2em;
  height: 2em;
  margin-left: -1em;
  margin-top: -1em;
  border: solid 1px #fff;
}

We can now better see how our planet rotates:

See the pen on CodePen.

The keyframe animation applied to all our orbits its:

@keyframes orbit {
  0%   { transform: rotateZ(0deg); }
  100% { transform: rotateZ(-360deg); }
}

To counteract this animation, undoing the undesirable rotation it applies to our planets, we define the following animation for our planet wrappers:

@keyframes invert {
  0%   { transform: rotateX(-90deg) rotateY(360deg) rotateZ(0deg); }
  100% { transform: rotateX(-90deg) rotateY(0deg) rotateZ(0deg); }
}

Now this is very difficult to visualize, and either you’re good at visualizing this mathematically, or you build it by trial and errors. It’s obvious that since the orbit animation rotates the galaxy around the Z-axis from 0 to 360 degrees, that the wrapper animation should rotate around some axis by 360 to 0 degrees (the opposite). By implementing that, and then fiddling with constant values for the other axes, you end up with a working animation. The square we drew around the wrapper <div> also helps a lot in identifying how the rotation must work.

Now we only need to apply this animation to the planet wrapper class .pos:

.pos {
  position: absolute;
  transform-style: preserve-3d;
  animation-name: invert;
  animation-iteration-count: infinite;
  animation-timing-function: linear;
}

There you go – the planets have now stopped rotating individually.

See the pen on CodePen.

Summary

What’s left to do? We can now add more planets with different sizes, orbit diameters and durations. We can add labels that show the planet name and orbit duration. But you will need no further CSS 3 tricks to accomplish this. In fact, Julian Garnier’s animation does all that and more. You can switch from 3D to 2D view (hint: remove the galaxy rotation) and switch labels on and off. Maybe it’s time to apply your knowledge of rounding borders, animated box-shadows, keyframe animations and CSS 3D transformations to your own project?

Good luck!