I'm attempting to create a simple loading animation of a moon orbiting a planet. I'm using 3d css to simulate an elliptical orbit but I can't get the animation to look how I would prefer, explained below. I feel I may have over complicated it along the way.
This is where I'm up to so far:
.outer {
width: vw;
height: vh;
display: flex;
justify-content: center;
align-items: center;
}
.inner {
width: 100px;
height: 100px;
transform: rotate(-25deg);
display: flex;
justify-content: center;
align-items: center;
}
.planet-container {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
transform: perspective(150px) rotateY(75deg);
transform-style: preserve-3d;
}
.planet-outer {
animation: planet 2s infinite;
transform-origin: 50% -25%;
transform-style: preserve-3d;
width: 100%;
height: 100%;
}
.planet {
width: 15%;
height: 15%;
background-color: black;
border-radius: 999px;
margin: 75% auto 0 auto;
transform: perspective(150px) rotateY(-75deg);
}
.back-circle {
background-color: blue;
border-radius: 999px;
position: absolute;
width: 40%;
height: 40%;
top: 50%;
left: 50%;
transform: perspective(150px) translate3d(-50%, -50%, 0px);
}
@keyframes planet {
0% {
transform: perspective(150px) rotate(0);
}
100% {
transform: perspective(150px) rotate(360deg);
}
}
<div class="outer">
<div class="loading-icon">
<div class="inner">
<div class="back-circle"></div>
<div class="planet-container">
<div class="planet-outer">
<div class="planet"></div>
</div>
</div>
</div>
</div>
</div>
And below is a quick diagram of my desired animation:
As you can see, the elliptical orbit & perspective is working well. However, the "moon" is scewed and flipping as it rotates, and is not obscured behind the "planet" on its return orbit. I understand why these aspects are not working correctly, but despite playing around for a while, I am unable to come up with a solid solution to these issues.
Any help would be appreciated, thanks!
Late to the party but here's my 2 cents:
I would use some CSS 3D for that purpose
.system
DIV parent that uses CSS perspective
.planet
.orbit
with a .moon
child element on its edge.orbit
on its X axis (by say 80deg).moon
is child of .orbit
counter rotate it on that same axis by 90deg.moon
pancake as it rotates around the planet — counter-rotate the moon by -360deg.system
by 45degExample:
* {
margin: 0;
box-sizing: border-box;
}
body {
overflow: hidden;
min-height: 100dvh;
}
.system {
perspective: 1000px;
transform-style: preserve-3d;
height: 180px;
aspect-ratio: 1;
rotate: 45deg;
margin: auto;
}
.planet,
.orbit,
.moon {
position: absolute;
transform-style: preserve-3d;
inset: 0;
height: calc(var(--size) * 1%);
margin: auto;
aspect-ratio: 1;
border-radius: 50%;
}
.planet {
--size: 50;
background: #0bf;
}
.orbit {
--size: 80;
--duration: 6s;
box-shadow: 0 0 0 2cqmin #5554, inset 0 0 0 2cqmin #5554;
animation: orbit calc(var(--duration)) linear infinite;
rotate: 1 0 0 80deg;
}
.moon {
--size: 24;
height: calc(var(--size) * 1%);
margin-left: calc(var(--size) * -0.5%);
background: #000;
animation: moon calc(var(--duration)) linear infinite;
rotate: 1 0 0 90deg;
}
@keyframes orbit { to { transform: rotate3d(0, 0, 1, 360deg); } }
@keyframes moon { to { transform: rotate3d(0, 1, 0, -360deg); } }
<div class="system">
<div class="planet"></div>
<div class="orbit">
<div class="moon"></div>
</div>
</div>
Not perfect (issues are not visible due to the slight 80deg orbit inclination) - but fine for this demo. Gimballing the moon would become pretty hard on more steep angles and would involve too much work to determine all the necessary X Y Z angles in order to keep the moon perfectly facing the camera during the animation. So, this seems quite fine. Obviously the perfect result would be putting the orbit at 90deg, but this slight inclination seems nicer visually.
For a similar concept see this answer.