3D✨ Premium

Floating Elements 3D

Three 60 px square tiles (indigo, magenta, cyan-green) in a row, rising and sinking 20 px while tilting in 3D on a 6 s loop, offset by 2 s from one tile to the next: they never move together, like objects floating on water. Pure CSS, zero JavaScript, held at different heights when the user reduces motion.

CSS3DFloat

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

Three figures of a floatation session — page of a sensory deprivation tank center — Floating Elements 3D example 1

① Three figures of a floatation session — page of a sensory deprivation tank center

WhenUnder "One hour of weightlessness", three tiles "60 minutes", "35 °C water", "500 kg of salt" float above the "Book a session" button, on a midnight-blue background.
WhyThe tiles' offset floating conveys the promised weightlessness without a picture of a tank; shapes drifting across the whole frame, like Floating Elements, would be too busy for a relaxation page.
Settings88 px tiles (instead of 60) with a 35% white border, 30 px gap; blue gradients (cornflower, turquoise, lavender); figure in 19 px bold and unit in 11 px; fixed waterline under the row.
Three fishing floats on the water — "Our spots" page of an angling club — Floating Elements 3D example 2

② Three fishing floats on the water — "Our spots" page of an angling club

WhenThree red-and-white floats "Spot 1", "Spot 2", "Spot 3" bob on the mill pond's waterline; below, the pond map with the three spots and the price of a day permit.
WhyThe slight 3D roll, offset from one float to the next, is that of floats resting on calm water.
Settings72 px tiles, 22 px corners, background cut cleanly at mid-height (linear-gradient(180deg, #e0312f 0 52%, #fdfdfb 52%)), dark text at the bottom; 44 px gap; row centered on the waterline.
Scrabble letters in midair — home page of a Scrabble club — Floating Elements 3D example 3

③ Scrabble letters in midair — home page of a Scrabble club

WhenThree beige tiles "J", "E", "U", with their small value in the corner (8, 1, 1), float above a wooden rack and the heading "Scrabble club — Tue & Thu, 2 pm".
WhyThree square tiles in a row, each floating at its own pace: exactly a player's rack, set in motion.
Settings84 px tiles, 9 px corners, cream #f6e7c1 → #e3cc95 gradient and an inner shadow at the bottom; letter in 44 px Georgia, value in a 13 px <sub>; fixed green grid mat and rack.

How it works

The .fx-0017-root root (#0a0a0f background, at least 300 px tall) centers a .floating-3d row (flex, 20 px gap) that carries a single camera for the three tiles: perspective: 800px. Each .floating-element is 60 × 60 px with 0.75 rem rounded corners and its own 135° gradient: indigo → violet, magenta → pink, cyan → green. All three play the same 6 s float3d animation, ease-in-out, forever.

The loop has four steps: at the start the tile is flat; at 25% it rises 20 px and tilts 10° on both axes; at 50% it is back at its height, turned 20° around the vertical axis; at 75% it sinks 20 px, tipped −10° forward; then it returns to rest. The offset comes from negative animation-delay values: 0 s, −2 s and −4 s. A negative delay starts the animation already under way, so from the very first paint the three tiles are a third of a loop apart, with no waiting and no synchronized start. Since the camera is shared and sits at the center of the row, the left tile is seen slightly from the right and the right tile slightly from the left: the same tilt reads differently on each of the three.

Measured in Chromium 151 and Firefox 153: about 3% of the block's pixels change every 0.8 s, two independent copies, 0 errors. Only transform is animated. Here each tile turns on its own under its parent's perspective, with no nested volume: even the test WebKit (Playwright 26.5), which flattens cubes and rings, renders the same tilts (0.5% difference from Chromium on the still frame). The real Safari was not verified.

Accessibility

  • Reduced motion: under prefers-reduced-motion: reduce, a block scoped to .fx-0017-root stops the three loops and sets each tile at a different step of the loop: the first 10 px higher and tilted, the second turned 20°, the third 10 px lower and tipped. The idea of floating objects remains, without motion. Measured in Chromium and Firefox: 0 running animations, 0% of pixels changing over 0.8 s (3% without the preference).
  • Continuous motion: the loop never stops; next to text people need to read, provide a way to pause it (WCAG 2.2.2), for instance animation-play-state: paused on a button or when hovering the row.
  • Contrast: the white digits reach 4.5:1 on indigo but 2.4 to 2.5:1 on cyan-green, below the 4.5:1 threshold for 16 px text. To put information there, darken the gradient or enlarge the text (24 px bold, 3:1 threshold).
  • No interaction: the tiles react to neither mouse, finger nor keyboard; if they carry useful figures, as in the first example, those are read as ordinary text.

Browser compatibility

CSS (3D transform under perspective, negative animation-delay, @keyframes), zero JavaScript, no dependencies. Measured in Chromium 151 and Firefox 153: same floating (0.01% difference on the still frame), two independent copies, 0 errors. WebKit 26.5 (Playwright's test engine): same tilts; the real Safari was not verified.

Chrome 36+✓ Full (measured)
Firefox 16+✓ Full (measured)
Safari✓ Not verified on a real Safari (test WebKit matches)
Edge 79+✓ Full (Chromium engine)
Mobile iOS✓ Not verified on a real Safari
Android Chrome✓ Full (Chromium engine)

Without 3D transforms, the tiles rise and sink flat, with no tilt; without animation, they stay aligned and still. Their content stays readable either way.

The code

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

index.html — structure
<div class="fx-0017-root">
  <div class="demo-3d">
    <div class="floating-3d">
      <div class="floating-element">1</div>
      <div class="floating-element">2</div>
      <div class="floating-element">3</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
Amplitude (CSS — @keyframes float3d) ±20 px, tilts of 10 to 20° ±8 px and 5° for barely visible floating; ±30 px for lighter objects. Keep the 0% and 100% steps identical for a seamless loop.
Duration (CSS — 6s in the animation of .floating-element) 6 s 8 to 10 s for a calm page. If you change it, keep the delays at one third and two thirds of the duration (−2.67 s and −5.33 s for 8 s).
Offset (CSS — animation-delay of :nth-child(2) and (3)) 0 s, −2 s, −4 s Delays of 0 give three synchronized tiles, like a single piece; irregular delays (−1.3 s, −4.1 s) look more natural. Negative values avoid a synchronized start on load.
Size and gap (CSS — width / height of .floating-element, gap of .floating-3d) 60 px, 20 px gap Between 72 and 90 px, a figure and its unit fit in the tile. Leave at least 20 px of gap: the tiles turn 20° and spill over a little on the sides.
Perspective (CSS — perspective of .floating-3d) 800px 400 px makes the tilt very visible; 1,500 px makes it almost flat. The camera sits at the center of the row: the closer it is, the more the edge tiles look seen from an angle.
Number of tiles (HTML and CSS) 3 For 4 tiles, add an element and a :nth-child(4) rule; spread the delays in quarter loops (0, −1.5 s, −3 s, −4.5 s for 6 s).

FAQ

A positive animation-delay would make tiles 2 and 3 wait 2 and 4 s, still and aligned, before moving. A negative delay starts the animation as if it had already been running for 2 or 4 s: from the first paint, the three tiles are at different moments of the loop.
Floating Elements scatters five glass shapes of different sizes across the whole frame and lets them drift flat, with no 3D, each on its own duration. Floating Elements 3D keeps three aligned tiles of the same size on a single offset loop, and tilts them in 3D: a calm row rather than a cloud.
Yes, but a target moving 40 px up and down is hard to hit. Pause the loop on hover and focus (.floating-3d:hover .floating-element, .floating-3d:focus-within .floating-element { animation-play-state: paused }) or keep the link beside it, like the booking button in the first example.