SolutionsCase StudiesAI ToolsResourcesAboutContact
Get Your Free AI Automation Audit Book a Free 30-Minute Strategy Call
Playground~/frontend Open editor

~/css/rotate-animations

7 CSS Rotate Animations

6 Pure CSS1 with JSPublished 2026-10-05Free · no sign-up

Seven rotations: two gears that mesh, planets on orbits of different speeds, a coin spinning in 3D, a badge with text running round a circle, a refresh icon that spins while it works, a six-faced cube and a disclosure chevron that turns with its open state.

01. Meshing Gears

RotateLoop

Two gears turn in opposite directions at speeds matched to their sizes, so their teeth appear to mesh. The teeth are a repeating conic gradient masked into a ring, and the smaller gear spins faster in proportion to its tooth count.

View code
<div class="ro1" role="img" aria-label="Two gears turning"><span class="g a"></span><span class="g b"></span></div>
.ro1 { position: relative; width: 170px; height: 120px; }
.ro1 .g { position: absolute; border-radius: 50%; background: radial-gradient(circle, #0e1118 0 18%, transparent 19%), repeating-conic-gradient(#94a3b8 0 15deg, transparent 0 30deg); -webkit-mask: radial-gradient(circle, transparent 0 17%, #000 18% 100%); mask: radial-gradient(circle, transparent 0 17%, #000 18% 100%); }
.ro1 .g::after { content: ""; position: absolute; inset: 12%; border-radius: 50%; background: #64748b; -webkit-mask: radial-gradient(circle, transparent 0 22%, #000 23%); mask: radial-gradient(circle, transparent 0 22%, #000 23%); }
.ro1 .a { left: 0; top: 10px; width: 100px; height: 100px; animation: ro1 6s linear infinite; }
.ro1 .b { left: 92px; top: 30px; width: 70px; height: 70px; animation: ro1 4.2s linear infinite reverse; }
@keyframes ro1 { to { transform: rotate(1turn); } }
@media (prefers-reduced-motion: reduce) { .ro1 .g { animation: none; } }

02. Orbiting Planets

RotateOrbit

Two planets circle a sun on rings of different sizes and speeds. Each orbit is a rotating ring element with the planet placed on its edge, so a single rotate animation moves the planet round the whole circle.

View code
<div class="ro2" role="img" aria-label="Two planets orbiting a sun"><span class="sun"></span><span class="ring r1"><i></i></span><span class="ring r2"><i></i></span></div>
.ro2 { position: relative; display: grid; place-items: center; width: 200px; height: 200px; }
.ro2 > span { grid-area: 1 / 1; }
.ro2 .sun { width: 36px; height: 36px; border-radius: 50%; background: radial-gradient(circle, #fde68a, #f59e0b); box-shadow: 0 0 24px #f59e0b; }
.ro2 .ring { border: 1px dashed #334155; border-radius: 50%; animation: ro2 linear infinite; }
.ro2 .r1 { width: 100px; height: 100px; animation-duration: 4s; }
.ro2 .r2 { width: 180px; height: 180px; animation-duration: 9s; }
.ro2 i { display: block; width: 14px; height: 14px; margin: -7px auto 0; border-radius: 50%; background: #38bdf8; }
.ro2 .r2 i { width: 20px; height: 20px; margin-top: -10px; background: #f472b6; }
@keyframes ro2 { to { transform: rotate(1turn); } }
@media (prefers-reduced-motion: reduce) { .ro2 .ring { animation: none; } }

03. Spinning Coin

Rotate3D

A coin spins on its vertical axis with two faces, heads and tails, using rotateY, preserve-3d and backface-visibility. A thin edge is faked with a box-shadow so it does not vanish completely when side-on.

View code
<div class="ro3" role="img" aria-label="A gold coin spinning"><span class="f">★</span><span class="b">5</span></div>
.ro3 { position: relative; width: 90px; height: 90px; transform-style: preserve-3d; animation: ro3 3s linear infinite; }
.ro3 span { position: absolute; inset: 0; display: grid; place-items: center; border-radius: 50%; background: radial-gradient(circle at 35% 30%, #fef3c7, #f59e0b 60%, #b45309); color: #78350f; font: 900 34px Inter, system-ui, sans-serif; backface-visibility: hidden; box-shadow: inset 0 0 0 5px #d97706; }
.ro3 .b { transform: rotateY(180deg); }
@keyframes ro3 { to { transform: rotateY(1turn); } }
@media (prefers-reduced-motion: reduce) { .ro3 { animation: none; } }

04. Rotating Circular Text Badge

RotateSVG text

Text set on a circle with SVG textPath turns slowly around a centre icon, a stamp-like badge for heroes and portfolio sites. The text is real SVG text, and the badge has a single accessible name so it is not read character by character.

View code
<a class="ro4" href="#contact" aria-label="Available for projects, get in touch"><svg viewBox="0 0 100 100" aria-hidden="true"><defs><path id="ro4p" d="M50 50 m-38 0 a38 38 0 1 1 76 0 a38 38 0 1 1 -76 0"/></defs><text><textPath href="#ro4p">AVAILABLE FOR PROJECTS • GET IN TOUCH •</textPath></text></svg><span aria-hidden="true">↗</span></a>
.ro4 { position: relative; display: grid; place-items: center; width: 150px; height: 150px; text-decoration: none; }
.ro4 svg { position: absolute; inset: 0; width: 100%; height: 100%; animation: ro4 14s linear infinite; }
.ro4 text { fill: #e2e8f0; font: 700 9.2px Inter, system-ui, sans-serif; letter-spacing: 1.4px; }
.ro4 span { display: grid; place-items: center; width: 58px; height: 58px; border-radius: 50%; background: #a3e635; color: #1a2e05; font-size: 24px; font-weight: 800; }
.ro4:hover svg { animation-duration: 5s; }
.ro4:focus-visible { outline: 2px solid #a3e635; outline-offset: 2px; border-radius: 50%; }
@keyframes ro4 { to { transform: rotate(1turn); } }
@media (prefers-reduced-motion: reduce) { .ro4 svg { animation: none; } }

05. Refresh Icon Spins on Click

RotateIcon

A refresh button whose arrows spin while the refresh runs and stop when it ends. The rotation runs through the button's aria-busy state, and the label changes to Refreshing so the state is in the text as well.

View code
<button class="ro5"><svg viewBox="0 0 24 24" aria-hidden="true"><path d="M20 11a8 8 0 0 0-14.9-3M4 4v4h4M4 13a8 8 0 0 0 14.9 3M20 20v-4h-4"/></svg><span>Refresh</span></button>
.ro5 { display: inline-flex; align-items: center; gap: 8px; padding: 10px 16px; border: 1px solid #d0d5dd; border-radius: 10px; background: #fff; color: #101828; font: 600 14px Inter, system-ui, sans-serif; cursor: pointer; }
.ro5 svg { width: 18px; height: 18px; fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
.ro5[aria-busy="true"] svg { animation: ro5 .8s linear infinite; }
.ro5:focus-visible { outline: 3px solid #84adff; outline-offset: 2px; }
@keyframes ro5 { to { transform: rotate(1turn); } }
@media (prefers-reduced-motion: reduce) { .ro5[aria-busy="true"] svg { animation-duration: 2.4s; } }
var b = document.querySelector('.ro5'), s = b.querySelector('span');
b.onclick = function () { if (b.getAttribute('aria-busy') === 'true') return; b.setAttribute('aria-busy', 'true'); s.textContent = 'Refreshing…'; setTimeout(function () { b.removeAttribute('aria-busy'); s.textContent = 'Refresh'; }, 1800); };

06. Rotating 3D Cube

Rotate3D

A six-faced cube turning on two axes, built from six squares placed with rotate and translateZ inside a preserve-3d parent. Each face is half the cube's size away from the centre, which is the one number that must match the face size.

View code
<div class="ro6" role="img" aria-label="A cube turning in 3D"><div class="c"><i class="f1">1</i><i class="f2">2</i><i class="f3">3</i><i class="f4">4</i><i class="f5">5</i><i class="f6">6</i></div></div>
.ro6 { width: 90px; height: 90px; perspective: 400px; }
.ro6 .c { position: relative; width: 100%; height: 100%; transform-style: preserve-3d; animation: ro6 8s linear infinite; }
.ro6 i { position: absolute; inset: 0; display: grid; place-items: center; border: 1px solid rgba(255,255,255,.4); background: rgba(99,102,241,.75); color: #fff; font: 800 24px Inter, system-ui, sans-serif; font-style: normal; }
.ro6 .f1 { transform: translateZ(45px); } .ro6 .f2 { transform: rotateY(90deg) translateZ(45px); background: rgba(236,72,153,.75); }
.ro6 .f3 { transform: rotateY(180deg) translateZ(45px); } .ro6 .f4 { transform: rotateY(-90deg) translateZ(45px); background: rgba(236,72,153,.75); }
.ro6 .f5 { transform: rotateX(90deg) translateZ(45px); background: rgba(20,184,166,.75); } .ro6 .f6 { transform: rotateX(-90deg) translateZ(45px); background: rgba(20,184,166,.75); }
@keyframes ro6 { from { transform: rotateX(-20deg) rotateY(0); } to { transform: rotateX(-20deg) rotateY(1turn); } }
@media (prefers-reduced-motion: reduce) { .ro6 .c { animation: none; transform: rotateX(-20deg) rotateY(-30deg); } }

07. Chevron Turns with Open State

RotateDisclosure

Disclosure chevrons that rotate 180 degrees when their details element opens, driven by the [open] attribute, so no script is involved. The rotation is a short transition rather than an animation, and it reverses when the panel closes.

View code
<div class="ro7"><details><summary>Shipping<span aria-hidden="true"></span></summary><p>Orders ship within two working days.</p></details><details><summary>Returns<span aria-hidden="true"></span></summary><p>Free returns within 30 days.</p></details></div>
.ro7 { box-sizing: border-box; width: 260px; max-width: 100%; border: 1px solid #e4e7ec; border-radius: 12px; background: #fff; font: 14px Inter, system-ui, sans-serif; }
.ro7 details + details { border-top: 1px solid #e4e7ec; }
.ro7 summary { display: flex; align-items: center; justify-content: space-between; padding: 14px 16px; color: #101828; font-weight: 700; cursor: pointer; list-style: none; }
.ro7 summary::-webkit-details-marker { display: none; }
.ro7 summary span { width: 9px; height: 9px; border-right: 2px solid #475467; border-bottom: 2px solid #475467; transform: rotate(45deg); transition: transform .3s ease; }
.ro7 details[open] summary span { transform: rotate(225deg); }
.ro7 summary:focus-visible { outline: 3px solid #84adff; outline-offset: -3px; }
.ro7 p { margin: 0; padding: 0 16px 14px; color: #475467; }
@media (prefers-reduced-motion: reduce) { .ro7 summary span { transition: none; } }

About these CSS Rotate Animations

Rotate around the right point

Rotation happens around transform-origin, the centre by default. Set it to the hinge, the axle or the bottom edge depending on what is turning.

Orbits are rotating parents

To move something round a circle, put it on the edge of a ring element and rotate the ring. One animation does the whole orbit, no maths needed.

3D needs three things

perspective on the parent, transform-style: preserve-3d on the rotating element, and backface-visibility: hidden on faces that should disappear when turned away.

Linear for loops, eased for one-offs

Continuous spins use linear timing so the speed never wobbles. Single turns, like a chevron or a gear on hover, feel better with ease-out.

Frequently asked questions

Can I rotate text on a circle without SVG?

Not easily. SVG textPath is the reliable way, as in the badge demo.

Why is the coin edge visible side-on?

A 3D coin has no thickness in CSS; an inset shadow fakes a rim so it does not vanish completely.

Do spinning elements need reduced motion handling?

Yes. Each demo stops or slows its rotation under prefers-reduced-motion.