Cascading Solar System
A few days ago I was nerd sniped by a Reddit post. The poster was making a visual representation of our solar system[1] and was having trouble getting the labels on the orbits to stay aligned correctly as the viewport was resized.
I don’t know how they were doing it, but I figured I’d take a stab at a responsive solar system in CSS.
See the Pen Cascading Solar System by Noah (@noleli) on CodePen.
A few thoughts, mostly about new(ish) CSS features, I had while making it:
- Grid is incredibly powerful, especially now with subgrid. Named grid lines and areas make placing items super clear. And using it to stack things feels so much more manageable than absolute positioning. Keeping things in regular flow means you can let the browser’s layout tools do the hard work for you!
- Did I have to use
:has()? No, I could have added planet-specific classes to each orbit. But is it convenient to place an orbit based on what planet is in it? You bet. - Similarly, nesting is technically optional but just so freaking handy.
- I was bitten by a Safari bug. Maybe it’s 262729. After much strife, I used a hacky JS solution. I don’t like it.
And then there are container queries. This doesn’t use them. I didn’t actually need container queries themselves, but container query units would have been extremely useful. Alas, I was already too dependent on intrinsic sizing, and switching to container-based/extrinsic sizing would have been disruptive.
What I wanted container query units for was to be able to get the height of an orbit element with cqh so that I could determine its radius. This would have unlocked a couple of things:
- Using a radial gradient to draw the orbit ring as the
background-imageof the orbit element itself rather than needing anorbit-ringchild - Setting the planets in motion by transforming them directly using the new CSS
sin()andcos()functions rather than nesting them inside anaxiscontainer
This has me wondering whether there’s an opportunity to allow cq* units even without size containment in some limited cases. Those cases would have to be limited to those where using CQ units can’t affect a child’s size. Perhaps something like this?
container-type: read-only;
My use cases — specifying gradients and transforms — satisfy that constraint, but I’m not sure if its too niche, or too confusing because CQ units would behave differently in different contexts. (Although, to be fair, percentages have been contextual forever.)
Of course, now I’m thinking about how you could make a more physically accurate model of the solar system using CQ units, trig functions, registered custom properties, and linear() to make accurate elliptical orbits. Watch this space for a new library, kepler.css[2].