← Back to gallery
CSSFeatured

Flip Card Front/Back Face Handling

Two faces share one plane via backface-visibility: hidden + a single rotateY/X transform, with :hover/:focus-within driving the flip. Three variants: a Y-axis profile card, an X-axis product tile, and a Quiet Swap opacity-crossfade fallback for reduced motion.

flip-cardbackface-visibilitypreserve-3drotateYrotateXfocus-withinprefers-reduced-motion

CSS 3D / Backface Visibility

3D Flip Card Front/Back Face Handling

Front and back faces occupy the same plane, use backface-visibility: hidden, and flip with a focus-safe reduced-motion fallback.

Y-axis rotation

Profile Card

Standard horizontal flip (rotateY). The mirrored back never bleeds through while the card rotates 180°. Keep the perspective wrapper separate from the card transform wrapper.

  • rotateY
  • backface
  • flip-card

X-axis rotation

Product Tile

Vertical flip (rotateX) for top-to-bottom card reveal. Same backface mechanics as a Y-flip — only the rotation axis changes, demonstrating that the technique is axis-agnostic.

  • rotateX
  • preserve-3d
  • axis-flip

Opacity crossfade

Quiet Swap

No rotation — faces crossfade via opacity for dense interfaces and reduced-motion users. Same DOM structure, gentler motion. The proper reduced-motion fallback pattern.

  • opacity
  • low-motion
  • fallback

Flip card inspector

Profile Card

hover card
Mina LeeDesigner
@minalee128 followers
  • rotateY
  • backface
  • flip-card

Standard horizontal flip (rotateY). The mirrored back never bleeds through while the card rotates 180°. Keep the perspective wrapper separate from the card transform wrapper.

Helped you ship something? 🐟 Send my cat a churu

.flip-card {
  perspective: 720px;
}

.flip-card__inner {
  position: relative;
  transform-style: preserve-3d;
  transition: transform 4.40s ease;
}

.flip-card:hover .flip-card__inner,
.flip-card:focus-within .flip-card__inner {
  transform: rotateY(180deg);
}

.flip-card__face {
  position: absolute;
  inset: 0;
  backface-visibility: hidden;
  transform: translateZ(0.01px);
}

.flip-card__face--back {
  transform: rotateY(180deg) translateZ(0.01px);
}

@media (prefers-reduced-motion: reduce) {
  .flip-card__inner { transition-duration: 1ms; }
}

How to make this

A CSS 3D flip card puts perspective on the outer wrapper, preserves 3D on the inner card, hides each face backface, and pre-rotates the back face 180 degrees.

html
1<div class="flip-card" tabindex="0">  <div class="flip-card__inner">    <section class="flip-card__face flip-card__face--front">      <strong>Mina Lee</strong><span>Designer</span>    </section>    <section class="flip-card__face flip-card__face--back">      <strong>@minalee</strong><span>128 followers</span>    </section>  </div></div> <style>.flip-card {  width: 220px;  aspect-ratio: 1.6;16  perspective: 720px;  outline-offset: 6px;}.flip-card__inner {  position: relative;  width: 100%;  height: 100%;23  transform-style: preserve-3d;  transition: transform 600ms cubic-bezier(.45,0,.55,1);}.flip-card:hover .flip-card__inner,.flip-card:focus .flip-card__inner {  transform: rotateY(180deg);}.flip-card__face {  position: absolute;  inset: 0;  display: grid;  place-content: center;  gap: .35rem;  border-radius: 16px;  color: white;  background: linear-gradient(135deg, #0f172a, #1e293b);39  backface-visibility: hidden;  -webkit-backface-visibility: hidden;  transform: translateZ(0.01px);}.flip-card__face--back {  background: linear-gradient(135deg, #312e81, #0f172a);  transform: rotateY(180deg) translateZ(0.01px);}.flip-card__face span { opacity: .72; }48@media (prefers-reduced-motion: reduce) {49  .flip-card__inner { transition-duration: 1ms; }}</style>

Annotated snippet

  1. Line 1The card is focusable so keyboard users can trigger the same visual state as hover. In production, make the card a real button or link when flipping reveals actionable content.
    PitfallHow do I make a flip card accessible for keyboard users?

    Do not rely on hover only. Use a focusable control when the flip reveals meaningful content, mirror the hover state with :focus or :focus-within, and keep the DOM order understandable. If both sides contain essential information, make that information available without requiring motion.

  2. Line 16perspective belongs on a parent that is not rotating. If the same element owns both perspective and transform, the depth cue becomes harder to reason about and sibling cards cannot share a stable camera.

    Only the perspective placement changes here. When perspective sits on the same element that rotates, the card stays a flat trapezoid; when it sits on a non-rotating parent, the same rotation reads as a 3D card pivoting toward the viewer.

    PitfallWhere should perspective go on a CSS flip card?

    Put perspective on the outer stage and rotate an inner wrapper. That separates the camera from the object being transformed, which makes the depth consistent and lets multiple cards share the same visual rules. The faces should stay inside the rotating wrapper.

  3. Line 23transform-style: preserve-3d keeps the front and back in the same 3D scene. Without it, children flatten into the card plane and the back face can appear like a simple overlay.
    PitfallWhere should perspective go on a CSS flip card?

    Put perspective on the outer stage and rotate an inner wrapper. That separates the camera from the object being transformed, which makes the depth consistent and lets multiple cards share the same visual rules. The faces should stay inside the rotating wrapper.

  4. Line 39backface-visibility: hidden prevents the reversed side of each face from bleeding through during the 90 degree crossover. Add the -webkit prefix because Safari still benefits from it on 3D card faces.

    Without backface hiding, both faces can be readable during the midpoint of the rotation.

    PitfallWhy does the back of my flip card show mirrored text?

    The card is missing backface-visibility: hidden on one or both faces, or Safari needs the -webkit-backface-visibility prefix. Apply it to every face and pre-rotate the back face by the same axis and angle the wrapper will use for the flip.

  5. Line 49The back face starts rotated 180 degrees so it becomes front-facing exactly when the inner wrapper flips. The tiny translateZ offset reduces z-fighting where both planes occupy the same depth.
    PitfallWhy does the back of my flip card show mirrored text?

    The card is missing backface-visibility: hidden on one or both faces, or Safari needs the -webkit-backface-visibility prefix. Apply it to every face and pre-rotate the back face by the same axis and angle the wrapper will use for the flip.

  6. Line 48Reduced motion keeps the state change but removes the long rotation. A near-instant transition is preferable to disabling focus or hover behavior entirely.
    PitfallWhat reduced-motion fallback should a flip card use?

    Keep the interaction but collapse the rotation duration under prefers-reduced-motion. For dense interfaces, consider replacing the 3D rotation with an opacity swap. Avoid removing the back content entirely, because that changes what keyboard and assistive-technology users can reach.

Other pitfalls

Are CSS 3D flip cards expensive to animate?
A single transform-based flip is usually cheap because it can run on the compositor. The expensive parts are large shadows, filters, big blurred backgrounds, or many cards flipping at once. Keep the card bounded and avoid animating layout, width, height, or filter values.
Advanced

Push inner face content forward with translateZ so the card flips with parallax depth

Same outer perspective, same rotateY flip on hover, same 600ms transition on both sides. Same 5s auto-cycle pretending to hover at 50% of the cycle. BEFORE keeps the inner title + subtitle flush against the face — when the card flips, the content slab looks like a printed sticker. AFTER pushes strong forward 22px and span forward 10px on the same preserve-3d stack — during the flip you see the title floating above the face with the subtitle one layer behind. Same 3D transform technique, just one more depth level used.

View explanation and full code21 lines

The base recipe handles the 3D flip mechanism — perspective, preserve-3d, backface-visibility, pre-rotated back face. The flip itself works, but the content INSIDE each face stays flat against the face surface. Production 3D card patterns (Apple product cards, Stripe pricing tiles) push inner content forward in the same 3D space via translateZ, so during the flip you see the title sitting "above" the card and the subtitle just behind it — true parallax depth on the same preserve-3d stack the slug already establishes. Just add transform-style: preserve-3d to the face (so it accepts 3D children), then translateZ on inner elements.

Append these rules inside the <style> block from the base snippet above.

css
/* Advanced: parallax depth on inner face content — extends the base recipe. */.flip-card__face {  transform-style: preserve-3d;}.flip-card__face strong {  display: inline-block;  transform: translateZ(22px);}.flip-card__face span {  display: inline-block;  transform: translateZ(10px);}/* Back face needs the same depth tree, applied AFTER its rotateY 180. */.flip-card__face--back strong { transform: translateZ(22px); }.flip-card__face--back span   { transform: translateZ(10px); }@media (prefers-reduced-motion: reduce) {  .flip-card__face strong,  .flip-card__face span,  .flip-card__face--back strong,  .flip-card__face--back span { transform: none; }}

Notes

Overview

Flip cards stack two faces on the same plane and reveal one side at a time by rotating the parent 180 degrees. The trick is backface-visibility: hidden on each face: when a face turns past 90 degrees its back faces the camera, and hiding the backface keeps the other face from ghosting through. Three variants ship: a horizontal Y-axis flip (the canonical profile card), a vertical X-axis flip (product reveal), and a Quiet Swap opacity crossfade for reduced motion.

When to use it

Reach for flip cards as a compact secondary view for same-thing content: stats on the back of a player card, terms on the back of a product tile, options on the back of a loyalty card. Skip it when the back face is wholly unrelated content — that should be a separate page or modal, not a magic flip. Skip flip cards in long lists; the cumulative rotation gets disorienting at scale.

How it works

Wrap the two faces in a container with perspective (the camera) and inside that an inner with transform-style: preserve-3d + a rotateY(0deg) transition. Position both faces absolutely on the same plane with backface-visibility: hidden. The back face starts pre-rotated by rotateY(180deg) so when the inner rotates 180 the back face arrives at 0 (visible) and the front face arrives at 180 (hidden by its backface). The flip is just a single transition on the inner’s transform — toggled by :hover, :focus-within, or a JS class.

Production gotchas

On :hover only, keyboard users can never see the back face — pair :hover with :focus-within always. Wrapping the card in a <button> or<a> gives you native focus + click without extra JS. Some Safari versions still need explicit -webkit-backface-visibility: hidden alongside the unprefixed version. If the back face shows a thin sliver of the front during rotation, that is a subpixel anti-alias artifact — add transform: translateZ(0.01px) to each face to force a unique z-depth.

Accessibility

Both faces should contain real DOM content (text, links) so screen readers can read the entire card regardless of which side is visible. prefers-reduced-motion: reduce replaces the rotation with an opacity crossfade, which is what the Quiet Swap variant ships as the reduced-motion-safe primary. Keyboard users need :focus-within on the card so Tab triggers the flip the same way a mouse hover would.

References

Implementation depth

The front and back faces should share one 3D plane with backface-visibility hidden. Drive the rotation from the parent so hover and focus-within produce the same state rather than building separate mouse and keyboard paths.

Avoid putting essential reading content only on the back face. On touch devices and reduced motion settings, the fallback should expose the information without requiring a precise hover state or a disorienting 180-degree flip.