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>
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%;
}
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;
}
By setting a --d
-variable (for diameter) per planet, using width: var(--d);
, we get:
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);
}
Let's ask ChatGPT to generate some nice radial-gradent
s 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;
}
And now we have:
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;
}
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%;
}
}
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:
... 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:
Top comments (48)
Can you give us the link to the final codepen?
It’s the embedded Pen, I didn’t upload a Pen with the AU-version.
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]
Yes,
offset-path
was added to mobile Safari in iOS 17 😟Well it works on my iPhone here:
developer.mozilla.org/en-US/docs/W...
So, it must be something else?
Not sure?
offset-distance
, maybe?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.
It works in mobile Safari on my iPhone, iOS 17.5.1 🤷♂️
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:
Weird, seems like it understands
offset-path
, but notcontent-box
, which might have been added later to the specs?!Yes. It might be the
content-box
issue: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! 😀
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')
Supported in all browsers:
caniuse.com/css-container-query-units
PLUTON!?
It’s not a planet anymore 🤓
no it is :I
Awesome animation and nice use of ChatGPT for the orbits!
Thanks!
As for learning purpose this article is awesome! Thank you! 👏🏼👏🏼👏🏼👏🏼👏🏼
Happy to hear that — thank you!
What is cqi?
It’s a container-query (the “cq”) unit, for the inline (“i”) dimension. If you use
contanter-type: inline-size
, then100cqi
is the total width of the container.Thank you!
Further reading if you're interested
developer.mozilla.org/en-US/docs/W...
Bravo, that's really cool.
Thanks!
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.
Thank you!
Here is my effort from a few years ago, using GSAP & CSS:
codepen.io/charles1971/pen/BaNyqYE
It is only the inner planets 🙂
Nice!
This is amazing & very cool.
Thank you!