DEV Community

Cover image for The Solar System in CSS
Mads Stoumann
Mads Stoumann

Posted on • Updated on

The Solar System in CSS

The Solar System has been done in CSS a lot of times — just search Codepen! So why do it again?

Because things get better and simpler — and we can now do a responsive solar system with just a few lines of CSS.

Let's start with some very basic markup:

<ol>
  <li class="sun"></li>
  <li class="mercury"></li>
  <li class="venus"></li>
  <li class="earth"></li>
  <li class="mars"></li>
  <li class="jupiter"></li>
  <li class="saturn"></li>
  <li class="uranus"></li>
  <li class="neptune"></li>
</ol>
Enter fullscreen mode Exit fullscreen mode

We use an ordered list, because the planets are in order.

Next, we unset the default <ol>-styles, and style it as a grid:

ol {
  all: unset;
  aspect-ratio: 1 / 1;
  container-type: inline-size;
  display: grid;
  width: 100%;
}
Enter fullscreen mode Exit fullscreen mode

Now, for the planet trajectories, we're going to use a "grid stack". Instead of position: absolute, and a bunch of translations, we can simply stack all the grid items with:

li {
  grid-area: 1 / -1;
  place-self: center;
}
Enter fullscreen mode Exit fullscreen mode

By setting a --d-variable (for diameter) per planet, using width: var(--d);, we get:

Trajectories

Cool! Let's add the planets using an ::after pseudo-element:

li::after {
  aspect-ratio: 1 / 1;
  background: var(--b);
  border-radius: 50%;
  content: '';
  display: block;
  width: var(--w, 2cqi);
}
Enter fullscreen mode Exit fullscreen mode

Let's ask ChatGPT to generate some nice radial-gradents for each planet — and while we're at it, let's tell it we're creating the Solar System and ask for planetary sizes between 1 and 6cqi — not completely accurate, but still maintaining a sizeable, recognizable difference:

.mercury {
  --b: radial-gradient(circle, #c2c2c2 0%, #8a8a8a 100%);
  --w: 2.0526cqi;
}

.venus {
  --b: radial-gradient(circle, #f4d03f 0%, #c39c43 100%);
  --w: 2.6053cqi;
}

.earth {
  --b: radial-gradient(circle, #3a82f7 0%, #2f9e44 80%, #1a5e20 100%);
  --w: 3.1579cqi;
}

.mars {
  --b: radial-gradient(circle, #e57373 0%, #af4448 100%);
  --w: 3.7105cqi;
}

.jupiter {
  --b: radial-gradient(circle, #d4a373 0%, #b36d32 50%, #f4e7d3 100%);
  --w: 4.8158cqi;
}

.saturn {
  --b: radial-gradient(circle, #e6dba0 0%, #c2a13e 100%);
  --w: 5.3684cqi;
}

.uranus {
  --b: radial-gradient(circle, #7de3f4 0%, #3ba0b5 100%);
  --w: 4.2632cqi;
}

.neptune {
  --b: radial-gradient(circle, #4c6ef5 0%, #1b3b8c 100%);
  --w: 6cqi;
}
Enter fullscreen mode Exit fullscreen mode

And now we have:

Solar System

To animate the planets with different trajectory speeds, we add:

li::after {
  /* previous styles */
  animation: rotate var(--t, 3s) linear infinite;
  offset-path: content-box;
}
Enter fullscreen mode Exit fullscreen mode

Notice the offset-path. That's the key to simplifying the trajectory-animations, because all we have to do to move the planet along the shape of the <li> is this:

@keyframes rotate {
  to {
    offset-distance: 100%;
  }
}
Enter fullscreen mode Exit fullscreen mode

And that's all! I asked ChatGPT to calculate the timings based on "Neptune", with a rotation-speed of 20s — and we get:


Conclusion

With just a few rules, we created a simple 2d version of the Solar System in pure CSS. If you want to dive deeper, you can:

  • use real distances and sizes (with calc())
  • add a transform: rotateX(angle) to the <ul> to make it pseudo-3D:

Basic 3D

... and maybe use matrix3d to "re-flatten" the planets?

Happy coding!


UPDATE, 27.08.24: Some readers have poined out, that the scales and distances are not correct. That is true, and is on purpose. The goal of this article is to show the powers of offset-path and grid-stacks.

However, if we were to calc the system dimensions with the Sun's width at 10cqi and the outer trajectory of Neptune at 100cqi, then we have an AU (Astronomical Unit) of 2.994cqi, and we get:

Scaled

Top comments (48)

Collapse
 
charlesr1971 profile image
Charles Robertson

Can you give us the link to the final codepen?

Collapse
 
madsstoumann profile image
Mads Stoumann • Edited

It’s the embedded Pen, I didn’t upload a Pen with the AU-version.

Collapse
 
charlesr1971 profile image
Charles Robertson

Hmmm. It’s just that there is no rotation, around the sun, in the embedded pen.
The planets are only rotating around their centres.
But maybe that’s because I am viewing it via mobile Safari on an iPhone 8+ [iOS 16.7]

Thread Thread
 
madsstoumann profile image
Mads Stoumann • Edited

Yes, offset-path was added to mobile Safari in iOS 17 😟

Thread Thread
 
charlesr1971 profile image
Charles Robertson

Well it works on my iPhone here:

developer.mozilla.org/en-US/docs/W...

So, it must be something else?

Thread Thread
 
madsstoumann profile image
Mads Stoumann

Not sure? offset-distance, maybe?

Thread Thread
 
charlesr1971 profile image
Charles Robertson • Edited

That’s the one.
Indeed, this is not supported, at all, by mobile Safari.

UPDATE:

Well, initially, there was a red cross through the safari icon, but I think this must have been related to non mobile Safari, because when I tried the tests at:

developer.mozilla.org/en-US/docs/W...

They all worked on my iPhone.

So, it isn’t that property.

Thread Thread
 
madsstoumann profile image
Mads Stoumann

It works in mobile Safari on my iPhone, iOS 17.5.1 🤷‍♂️

Thread Thread
 
charlesr1971 profile image
Charles Robertson • Edited

OK. It must be something to do with my version of iOS at 16.7?

UPDATE:

I have a feeling it maybe something to do with the unit cqi.
Now it says that it came in in iOS 16, but it might have been 16.8 or something.

Whatever is going on, my version doesn’t seem to be understanding the correct location of each planet’s rotational centre, which I guess is the centre of the canvas, where the sun is.

Very strange.

Maybe I will update my iOS to 16.7.10. This is the highest version I can update to on my iPhone 8+.

This is what I see, after I have turned the animation off:

Image description

Thread Thread
 
madsstoumann profile image
Mads Stoumann • Edited

Weird, seems like it understands offset-path, but not content-box, which might have been added later to the specs?!

Thread Thread
 
charlesr1971 profile image
Charles Robertson • Edited

Yes. It might be the content-box issue:

Image description

I have added a value that path-offset understands, and I get this, which is on the right track, but still not right:

codepen.io/charles1971/pen/gONjrJa

The planets are now all gas giants! 😀

Collapse
 
the_riz profile image
Rich Winter

It's great that you're providing the defaults in case a browser doesn't understand CSS variables, but I don't that any browser that has that problem would understand cqi. (I could be wrong, but I would think cqi to be to "new')

Collapse
 
madsstoumann profile image
Mads Stoumann

Supported in all browsers:
caniuse.com/css-container-query-units

Collapse
 
muhyilmaz profile image
MUHAMMED YILMAZ

PLUTON!?

Collapse
 
madsstoumann profile image
Mads Stoumann

It’s not a planet anymore 🤓

Collapse
 
muhyilmaz profile image
MUHAMMED YILMAZ

no it is :I

Collapse
 
codycodes profile image
Cody Antonio Gagnon

Awesome animation and nice use of ChatGPT for the orbits!

Collapse
 
madsstoumann profile image
Mads Stoumann

Thanks!

Collapse
 
ed1nh0 profile image
Edson Jr.

As for learning purpose this article is awesome! Thank you! 👏🏼👏🏼👏🏼👏🏼👏🏼

Collapse
 
madsstoumann profile image
Mads Stoumann

Happy to hear that — thank you!

Collapse
 
shikkaba profile image
Me

What is cqi?

Collapse
 
madsstoumann profile image
Mads Stoumann

It’s a container-query (the “cq”) unit, for the inline (“i”) dimension. If you use contanter-type: inline-size, then 100cqi is the total width of the container.

Collapse
 
shikkaba profile image
Me

Thank you!

Thread Thread
 
link2twenty profile image
Andrew Bone

Further reading if you're interested

developer.mozilla.org/en-US/docs/W...

Collapse
 
greenersoft profile image
GreenerSoft

Bravo, that's really cool.

Collapse
 
madsstoumann profile image
Mads Stoumann

Thanks!

Collapse
 
king_triton profile image
King Triton

This CSS Solar System demo showcases how simple techniques can create a visually appealing model. Leveraging grid and offset-path is a clever way to achieve smooth animations and responsive design.

Collapse
 
madsstoumann profile image
Mads Stoumann

Thank you!

Collapse
 
charlesr1971 profile image
Charles Robertson

Here is my effort from a few years ago, using GSAP & CSS:

codepen.io/charles1971/pen/BaNyqYE

It is only the inner planets 🙂

Collapse
 
madsstoumann profile image
Mads Stoumann

Nice!

Collapse
 
machineno15 profile image
Tanvir Shaikh

This is amazing & very cool.

Collapse
 
madsstoumann profile image
Mads Stoumann

Thank you!

Collapse
 
graham_mcmahon_653954877c profile image
Graham McMahon

Not bad, but Jupiter is too small relative to Saturn, Uranus and Neptune

Collapse
 
the_riz profile image
Rich Winter

Well, ditto the sun. And where's the Jupiter spot? And where is the Saturn ring, and, and, and...

Collapse
 
madsstoumann profile image
Mads Stoumann • Edited

I know, see the Update 😉

Collapse
 
madsstoumann profile image
Mads Stoumann • Edited

I know, see the Update 😉

Collapse
 
mayowakalejaiye profile image
mayowa-kalejaiye

Brilliant

Collapse
 
madsstoumann profile image
Mads Stoumann

Thanks!!

Collapse
 
eyuel_liyew_a3ec4 profile image
Tajebe Liyew

Wow

Collapse
 
madsstoumann profile image
Mads Stoumann

Thanks!

Collapse
 
syedmuhammadaliraza profile image
Syed Muhammad Ali Raza

Collapse
 
madeofclay profile image
Adam

2d version == Flatlands! Or… flat spaces?

Though I will say, toy projects/demos like this are one of the times where using id selectors makes sense, imo. Same net result.

Great stuff!

Collapse
 
madsstoumann profile image
Mads Stoumann

Thanks!