20 CSS Image Hover Effects 20 / 20

CSS Image Card Flip 3D Animation Hover

Cards that rotate 180deg on their Y-axis to reveal a back face with descriptive content, driven entirely by CSS 3D transforms.

Pure CSS MIT licensed
Live Demo Open in tab
Open in playground

The code

<div class="ih-20">
  <div class="ih-20__grid">
    <div class="ih-20__scene">
      <div class="ih-20__flipper">
        <div class="ih-20__front">
          <div class="ih-20__front-img ih-20__front-img--1"><span class="ih-20__face-icon">🔭</span></div>
          <div class="ih-20__front-label">
            <p class="ih-20__front-name">Cosmos Explorer</p>
            <p class="ih-20__front-cat">Astrophotography</p>
          </div>
          <span class="ih-20__hint">Hover to flip</span>
        </div>
        <div class="ih-20__back ih-20__back--1">
          <span class="ih-20__back-icon">🌌</span>
          <p class="ih-20__back-title">20-Week Course</p>
          <p class="ih-20__back-desc">Master astrophotography from light pollution basics to deep-sky stacking in Photoshop.</p>
          <button class="ih-20__back-cta">Enroll Now</button>
        </div>
      </div>
    </div>
    <div class="ih-20__scene">
      <div class="ih-20__flipper">
        <div class="ih-20__front">
          <div class="ih-20__front-img ih-20__front-img--2"><span class="ih-20__face-icon">🌿</span></div>
          <div class="ih-20__front-label">
            <p class="ih-20__front-name">Bio Systems</p>
            <p class="ih-20__front-cat">Botany Research</p>
          </div>
          <span class="ih-20__hint">Hover to flip</span>
        </div>
        <div class="ih-20__back ih-20__back--2">
          <span class="ih-20__back-icon">🧬</span>
          <p class="ih-20__back-title">Lab Access</p>
          <p class="ih-20__back-desc">12 months of virtual lab sessions with live microscopy and specimen archive access.</p>
          <button class="ih-20__back-cta">Join Lab</button>
        </div>
      </div>
    </div>
    <div class="ih-20__scene">
      <div class="ih-20__flipper">
        <div class="ih-20__front">
          <div class="ih-20__front-img ih-20__front-img--3"><span class="ih-20__face-icon">🎭</span></div>
          <div class="ih-20__front-label">
            <p class="ih-20__front-name">Digital Arts</p>
            <p class="ih-20__front-cat">Creative Studio</p>
          </div>
          <span class="ih-20__hint">Hover to flip</span>
        </div>
        <div class="ih-20__back ih-20__back--3">
          <span class="ih-20__back-icon">🎨</span>
          <p class="ih-20__back-title">Creator Pack</p>
          <p class="ih-20__back-desc">Unlimited generative art tools, 500+ premium assets, and weekly critique sessions.</p>
          <button class="ih-20__back-cta">Get Access</button>
        </div>
      </div>
    </div>
  </div>
</div>
.ih-20,.ih-20 *,.ih-20 *::before,.ih-20 *::after{margin:0;padding:0;box-sizing:border-box}
.ih-20 ::selection{background:#34d399;color:#000}
.ih-20{
  --accent:#34d399;--accent2:#818cf8;--bg:#07070f;--text:#f1f5f9;--muted:#64748b;
  --duration:0.65s;--ease:cubic-bezier(0.45,0,0.55,1);
  font-family:system-ui,sans-serif;background:var(--bg);padding:40px 24px;
  min-height: 100vh;display:flex;align-items:center;justify-content:center;
  perspective:1000px;
}
.ih-20__grid{display:grid;grid-template-columns:repeat(3,1fr);gap:20px;max-width:780px;width:100%}

.ih-20__scene{perspective:800px;aspect-ratio:3/4}
/* The flipper: transform-style:preserve-3d is the key */
.ih-20__flipper{
  position:relative;width:100%;height:100%;
  transform-style:preserve-3d;
  transition:transform var(--duration) var(--ease);
  cursor:pointer;
}
.ih-20__scene:hover .ih-20__flipper{transform:rotateY(180deg)}

/* Both faces share absolute positioning and backface-visibility:hidden */
.ih-20__front, .ih-20__back{
  position:absolute;inset:0;border-radius:16px;overflow:hidden;
  backface-visibility:hidden;-webkit-backface-visibility:hidden;
  display:flex;flex-direction:column;justify-content:flex-end;
}
/* Back face pre-rotated so it shows on flip */
.ih-20__back{transform:rotateY(180deg);flex-direction:column;justify-content:center;align-items:center;padding:20px}

.ih-20__front-img{
  position:absolute;inset:0;display:flex;align-items:center;justify-content:center;
}
.ih-20__front-img--1{background:linear-gradient(145deg,#1e1b4b,#312e81,#4338ca,#818cf8)}
.ih-20__front-img--2{background:linear-gradient(145deg,#052e16,#065f46,#059669,#34d399)}
.ih-20__front-img--3{background:linear-gradient(145deg,#3b0764,#6b21a8,#9333ea,#e879f9)}

.ih-20__back--1{background:linear-gradient(135deg,#13103a,#1e1b4b)}
.ih-20__back--2{background:linear-gradient(135deg,#031b10,#052e16)}
.ih-20__back--3{background:linear-gradient(135deg,#230335,#3b0764)}

.ih-20__face-icon{font-size:56px;opacity:0.35;position:relative;z-index:1}
.ih-20__front-label{position:relative;z-index:1;padding:16px;background:linear-gradient(to top,rgba(0,0,0,0.8),transparent)}
.ih-20__front-name{font-size:14px;font-weight:700;color:var(--text)}
.ih-20__front-cat{font-size:10px;color:var(--muted);margin-top:2px}

/* Back content */
.ih-20__back-icon{font-size:36px;margin-bottom:12px}
.ih-20__back-title{font-size:15px;font-weight:800;color:var(--text);text-align:center;margin-bottom:8px}
.ih-20__back-desc{font-size:11px;color:var(--muted);text-align:center;line-height:1.5;margin-bottom:14px}
.ih-20__back-cta{
  padding:8px 18px;border-radius:24px;
  font-size:11px;font-weight:700;letter-spacing:0.05em;
  color:#000;background:var(--accent);border:none;cursor:pointer;
  transition:transform 0.2s ease,box-shadow 0.2s ease;
}
.ih-20__back-cta:hover{transform:scale(1.04);box-shadow:0 0 16px rgba(52,211,153,0.4)}
.ih-20__back--3 .ih-20__back-cta{background:#e879f9;color:#000}
.ih-20__back--3 .ih-20__back-cta:hover{box-shadow:0 0 16px rgba(232,121,249,0.4)}

/* Flip hint badge */
.ih-20__hint{
  position:absolute;top:10px;right:10px;z-index:2;
  background:rgba(255,255,255,0.07);border:1px solid rgba(255,255,255,0.1);
  border-radius:20px;padding:3px 8px;font-size:9px;font-weight:700;color:var(--muted);
  transition:opacity 0.3s ease;
}
.ih-20__scene:hover .ih-20__hint{opacity:0}

@media(prefers-reduced-motion:reduce){.ih-20__flipper{transition:none}.ih-20__scene:hover .ih-20__flipper{transform:none}}

How this works

The card uses a three-layer structure: a .scene with perspective: 800px, a .flipper with transform-style: preserve-3d, and two face divs. The back face is pre-rotated with transform: rotateY(180deg). Both faces have backface-visibility: hidden, which hides each face when it is rotated beyond 90deg from the viewer. On hover, the flipper element transitions to rotateY(180deg), bringing the back face into view and hiding the front.

The transform-style: preserve-3d on the flipper is the critical property — without it, both faces flatten into 2D and the flip degenerates into a scale-to-zero then scale-from-zero effect. The perspective on the scene parent provides the 3D depth context without affecting the layout of surrounding elements.

Customize

  • Switch from Y-axis to X-axis flip by changing rotateY(180deg) to rotateX(180deg) on both the back face and the hover state.
  • Adjust flip speed with --duration: 0.4s for a snappy pop or 0.9s for a slow cinematic turn.
  • Add a slight scale(1.03) at the midpoint using keyframes on the flipper to make the card appear to grow during the flip.
  • For an "open book" effect, use two rotateY(90deg) stages (first half and second half) coordinated with an animation rather than a transition.
  • Place a video element on the back face that starts playing when the flip is triggered via a short JavaScript transitionend listener.

Watch out for

  • backface-visibility: hidden requires the -webkit- prefix in Safari — always include -webkit-backface-visibility: hidden alongside the standard property.
  • overflow: hidden on the flipper element breaks transform-style: preserve-3d in all browsers — never combine these two properties on the same element.
  • On Firefox, elements inside a 3D-transformed container may render with subpixel artefacts on the face edges — a 1px transparent border (border: 1px solid transparent) on the face elements often resolves this.

Browser support

ChromeSafariFirefoxEdge
36+ 9+ (-webkit- prefixes required) 16+ 36+

Always include -webkit-backface-visibility and -webkit-transform-style for Safari; test flip direction on iOS where perspective can behave differently.

Search CodeFronts

Loading…