3D✨ Premium

3D Carousel

Six small 80 × 60 px gradient tiles turn in a ring around a vertical axis, one turn every 10 s; their back sides are hidden, so you only see the two or three tiles facing you. The ring stops on hover, on keyboard focus and on a finger tap, so you can read the tile in front. Pure CSS, zero JavaScript, still when the user reduces motion.

CSS3DAnimation

Updated

This effect is part of Effect.Labs — 840 vanilla effects, some free, some premium. 3D has 50 effects, including 8 free. Explore the category →

3 usage examples

Rotating stations for an Olympic day — elementary school page — 3D Carousel example 1

① Rotating stations for an Olympic day — elementary school page

WhenOn Jules-Ferry school's page, under "Our Olympic day", six stations turn: relay, long jump, throwing, orienteering, tug of war, bike course; below, "Each class spends 20 minutes at each station".
WhyA ring that always comes back to the same station shows classes rotating from one post to the next; a grid of six boxes does not say that you move around.
SettingsOriginal gradients, station names on two lines when needed (text-align: center, 1.15 line height); ring enlarged ×1.3 with transform: scale(1.3) on .demo-3d (above the perspective, the 3D stays intact).
Crop rotation on six plots — teaching page of an organic market garden — 3D Carousel example 2

② Crop rotation on six plots — teaching page of an organic market garden

When"Crop rotation on our six plots" page of Ferme du Pré Vert: on the right, the ring of crop families (leafy greens, root crops, legumes, fruiting crops, green manure, fallow); on the left, "One plot changes family every year".
WhyThe ring's endless cycle is the very principle of crop rotation; hiding the back sides keeps only "this year's" families on screen.
SettingsOne color per family (green, orange, yellow-green, red, teal, brown) in 135° gradients; 11.5 px text; ring enlarged ×1.3; fixed elliptical shadow under the ring.
On-call pharmacies in the area — website of a rural district's pharmacists — 3D Carousel example 3

③ On-call pharmacies in the area — website of a rural district's pharmacists

When"This Sunday: Pharmacie du Marché, Saint-Pierre"; the ring cycles through the six pharmacies on the rota. Hovering a tile stops the ring on it and shows its address under the ring.
WhyThe on-call rota is a rotation: the ring shows it at a glance, and pausing on hover lets you read the pharmacy face-on without a button.
SettingsGreen tiles, name in bold and town in 9 px; the on-call pharmacy ringed in gold (box-shadow: inset 0 0 0 2px #fcd34d); a small scene script writes the address of the hovered or tapped tile under the ring; ring enlarged ×1.3.

How it works

The .fx-0004-root root (#0a0a0f background, at least 300 px tall) holds a 280 × 180 px .rcar-stage that carries the camera (perspective: 800px). The .rcar-ring is only 80 × 60 px, the size of one tile: it keeps its children in 3D (transform-style: preserve-3d) and turns from rotateY(0) to rotateY(360deg) in 10 s, linear, forever (the rcarSpin animation). The six .rcar-tile elements are stacked at the center, then placed with :nth-child: rotateY(0deg), 60deg… 300deg, each followed by translateZ(100px). Each tile has its own 135° gradient and 0.75 rem rounded corners.

Every tile has backface-visibility: hidden: as soon as a tile goes past 90° and shows its back, it disappears. With six tiles 60° apart on a 100 px radius, you always see the front tile and its two neighbors at an angle, with gaps behind: the ring reads without a clutter of mirrored tiles. The pause is one rule: .rcar-ring:hover and .rcar-stage:focus .rcar-ring set animation-play-state: paused. The stage has tabindex="0": the Tab key reaches it (2 px #a5b4fc outline on keyboard focus), and a finger tap gives it focus too. Measured in Chromium 151 and Firefox 153: 8.1% of pixels change over 0.8 s while the ring turns, 0% on hover, 0% on keyboard focus, 0% after a touch tap; it resumes when the pointer leaves or focus moves elsewhere.

The classes use the rcar- prefix rather than .carousel and .carousel-item: those are Bootstrap's names, and its .carousel-item { display: none } rule would hide the tiles on a site that loads it. The animation only touches transform (handled by the compositor). Two copies on one page turn and pause independently. Playwright's WebKit flattens all CSS 3D, even a reference cube: rendering on a real Safari was not verified.

Accessibility

  • Reduced motion: under prefers-reduced-motion: reduce, a block scoped to .fx-0004-root removes the animation: the ring stays still, tile 1 facing front and its two neighbors at an angle. Measured in Chromium and Firefox: 0 running animations, 0% of pixels changing over 0.8 s.
  • Keyboard and touch: the Tab key reaches the stage and the ring stops while it has focus (outline visible with the keyboard); on touch screens, a tap stops it and a tap elsewhere restarts it. Rewrite the group label (aria-label) in your page's language.
  • Contrast: the 12 px white labels reach 4.5:1 on indigo, but drop to 2.2:1 on amber and 2.4:1 on cyan, below the 4.5:1 threshold for text this size. Darken those gradients or set the text to 18 px bold.
  • Content: a tile that has turned to the back is hidden, so it leaves the screen for a moment, but its text stays in the HTML and a screen reader reads all six. If the tiles lead somewhere, make them links and keep the list readable elsewhere: a turning tile is a moving target.

Browser compatibility

CSS (3D transform, preserve-3d, backface-visibility, perspective, animation-play-state), zero JavaScript, no dependencies. Measured in Chromium 151 and Firefox 153: same ring (0.26% difference on the still frame), pause on hover, focus and touch, two independent copies, 0 errors. Playwright's WebKit 26.5 flattens all CSS 3D: the real Safari was not verified.

Chrome 36+✓ Full (measured)
Firefox 16+✓ Full (measured)
Safari✓ Not verified on a real Safari
Edge 79+✓ Full (Chromium engine)
Mobile iOS✓ Not verified on a real Safari
Android Chrome✓ Full (Chromium engine, pauses on tap)

Without preserve-3d, the six tiles collapse at the center of the stage and overlap; without backface-visibility, the far tiles show mirrored. The tiles' text stays in the page.

The code

HTML structure to paste into your page (the CSS + JS come with your purchase):

index.html — structure
<div class="fx-0004-root">
  <div class="demo-3d">
    <div class="rcar-stage" tabindex="0" role="group" aria-label="…">
      <div class="rcar-ring">
        <div class="rcar-tile">Item 1</div> … (6 tiles)
      </div>
    </div>
  </div>
</div>

One-time payment, no subscription — the code is yours forever

Customize

Options passed to the API or data-* attributes:

Option / propertyDefaultEffect
Speed (CSS — 10s in the animation of .rcar-ring) 10 s per turn 15 to 20 s if the tiles carry text to read; 6 s for a plain ornament. Keep linear.
Radius (CSS — translateZ(100px) in the six .rcar-tile:nth-child(n) rules) 100 px Larger (140 px), the tiles spread out and the ring widens: widen .rcar-stage too. Below 70 px, six 80 px tiles overlap.
Number of tiles (HTML and CSS) 6, every 60° For 8 tiles: one angle every 45° and a radius of at least 100 px. Each tile has its own :nth-child rule (angle and gradient).
Back side (CSS — backface-visibility of .rcar-tile) hidden visible also shows the far tiles, mirrored: a full ring but reversed text. Keep hidden as soon as the tiles carry words.
Pause (CSS — the .rcar-ring:hover, .rcar-stage:focus .rcar-ring rule) hover, keyboard focus, finger tap To let only the keyboard and hover stop it (not a mouse click), add .rcar-stage:focus:not(:focus-visible) .rcar-ring { animation-play-state: running }, as in the scenes above. To never stop it, delete the rule and the tabindex.
Tile size (CSS — width / height of .rcar-ring and .rcar-tile) 80 × 60 px Change both rules together. For long labels, 100 × 70 px with a 120 px radius.

FAQ

Because their back sides are hidden (backface-visibility: hidden): a tile turned past 90° shows its back and disappears. You see the front tile and its two neighbors; the others reappear as they come back around. That is intended: words never show up mirrored on screen.
Yes. The stage has tabindex="0": a finger tap gives it focus, and the .rcar-stage:focus .rcar-ring rule pauses the ring (measured: 0% of pixels changing after the tap). A tap elsewhere on the page removes focus and it starts again.
.carousel and .carousel-item are Bootstrap classes. On a site that loads Bootstrap, its .carousel-item { display: none } rule would hide the tiles, and its transitions would mix into the ring. The rcar- prefix avoids the clash; keep a prefix if you rename.