20 CSS Cards16 / 20

Pure CSSMIT licensed

3D Flip Business Card

Landscape business card that flips on hover AND focus-within (keyboard-accessible). Front shows avatar + name, back shows email/phone/site links. Reduced-motion disables the flip.

Published Updated

Live Demo
Try it

The code

<section class="card-16">
  <div class="card-16__card" tabindex="0" aria-label="Business card for Alex Chen — flip to see contact details">
    <div class="card-16__inner">
      <div class="card-16__face card-16__front">
        <div class="card-16__brand" aria-hidden="true">
          <span class="card-16__mark"></span>
          <span class="card-16__brandname">CHEN &amp; CO</span>
        </div>
        <div class="card-16__id">
          <h3 class="card-16__name">Alex Chen</h3>
          <p class="card-16__role">Principal Designer</p>
        </div>
        <span class="card-16__hint">Hover to flip</span>
      </div>
      <div class="card-16__face card-16__back">
        <span class="card-16__backbrand">CHEN &amp; CO</span>
        <address class="card-16__contact">
          <div class="card-16__row">
            <svg class="card-16__ico" aria-hidden="true" focusable="false" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M4 4h16c1.1 0 2 .9 2 2v12c0 1.1-.9 2-2 2H4c-1.1 0-2-.9-2-2V6c0-1.1.9-2 2-2z"/><polyline points="22,6 12,13 2,6"/></svg>
            <a href="mailto:alex@chen.co">alex@chen.co</a>
          </div>
          <div class="card-16__row">
            <svg class="card-16__ico" aria-hidden="true" focusable="false" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M22 16.92v3a2 2 0 0 1-2.18 2 19.79 19.79 0 0 1-8.63-3.07 19.5 19.5 0 0 1-6-6 19.79 19.79 0 0 1-3.07-8.67A2 2 0 0 1 4.11 2h3a2 2 0 0 1 2 1.72 12.84 12.84 0 0 0 .7 2.81 2 2 0 0 1-.45 2.11L8.09 9.91a16 16 0 0 0 6 6l1.27-1.27a2 2 0 0 1 2.11-.45 12.84 12.84 0 0 0 2.81.7A2 2 0 0 1 22 16.92z"/></svg>
            <a href="tel:+14155550142">+1 (415) 555-0142</a>
          </div>
          <div class="card-16__row">
            <svg class="card-16__ico" aria-hidden="true" focusable="false" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><line x1="2" y1="12" x2="22" y2="12"/><path d="M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z"/></svg>
            <a href="#site">alexchen.design</a>
          </div>
        </address>
      </div>
    </div>
  </div>
</section>
.card-16 {
  width: 100%;
  min-height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: clamp(28px, 5vw, 56px) clamp(20px, 4vw, 40px);
  box-sizing: border-box;
  background: radial-gradient(ellipse at 30% 20%, #1e293b 0%, transparent 60%), radial-gradient(ellipse at 80% 80%, #0f172a 0%, transparent 60%), #050815;
  font-family: 'Inter', system-ui, sans-serif;
  --focus: #f5d97b;
  --gold: #d4b063;
  --gold-lite: #f5d97b;
}

.card-16 *,
.card-16 *::before,
.card-16 *::after {
  box-sizing: border-box;
}

.card-16__card {
  width: 360px;
  height: 220px;
  perspective: 1000px;
  border-radius: 14px;
}

.card-16__card:focus-visible {
  outline: 2px solid var(--focus);
  outline-offset: 6px;
  border-radius: 14px;
}

.card-16__inner {
  position: relative;
  width: 100%;
  height: 100%;
  transform-style: preserve-3d;
  transition: transform 0.7s cubic-bezier(0.34, 1.2, 0.64, 1);
  box-shadow: 0 30px 60px -12px rgba(0, 0, 0, 0.6), 0 18px 36px -18px rgba(212, 176, 99, 0.35);
}

.card-16__card:hover .card-16__inner,
.card-16__card:focus-within .card-16__inner {
  transform: rotateY(180deg);
}

.card-16__face {
  position: absolute;
  inset: 0;
  -webkit-backface-visibility: hidden;
  backface-visibility: hidden;
  border-radius: 14px;
  padding: 26px 28px;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  background: linear-gradient(135deg, rgba(212, 176, 99, 0.14) 0%, transparent 40%, transparent 60%, rgba(212, 176, 99, 0.06) 100%), linear-gradient(160deg, #16213e 0%, #0f172a 50%, #050815 100%);
  border: 1px solid rgba(212, 176, 99, 0.28);
}

.card-16__face::before {
  content: '';
  position: absolute;
  top: 0;
  right: 0;
  width: 60%;
  height: 60%;
  background: radial-gradient(circle at top right, rgba(245, 217, 123, 0.18), transparent 60%);
  pointer-events: none;
}

.card-16__front {
  justify-content: space-between;
}

.card-16__back {
  transform: rotateY(180deg);
  justify-content: space-between;
}

.card-16__brand {
  display: flex;
  align-items: center;
  gap: 10px;
}

.card-16__mark {
  width: 32px;
  height: 32px;
  border-radius: 50%;
  background: linear-gradient(135deg, #f5d97b 0%, #d4b063 50%, #9a7a3d 100%);
  box-shadow: inset 0 -2px 4px rgba(0, 0, 0, 0.25), inset 0 2px 4px rgba(255, 255, 255, 0.3), 0 2px 6px rgba(212, 176, 99, 0.35);
  position: relative;
}

.card-16__mark::before {
  content: '';
  position: absolute;
  inset: 8px;
  border-radius: 50%;
  background: linear-gradient(135deg, #050815, #16213e);
}

.card-16__mark::after {
  content: 'A';
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: Georgia, 'Times New Roman', serif;
  font-size: 15px;
  font-weight: 700;
  color: #f5d97b;
  text-shadow: 0 1px 2px rgba(0,0,0,0.6);
}

.card-16__brandname {
  font-family: Georgia, 'Times New Roman', serif;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.24em;
  color: var(--gold);
  text-transform: uppercase;
}

.card-16__id {
  margin-bottom: 12px;
}

.card-16__name {
  font-family: Georgia, 'Times New Roman', serif;
  font-size: 26px;
  font-weight: 700;
  margin: 0 0 4px;
  color: #f8fafc;
  letter-spacing: -0.005em;
  line-height: 1.1;
}

.card-16__role {
  font-size: 11px;
  font-weight: 500;
  color: rgba(245, 217, 123, 0.85);
  margin: 0;
  letter-spacing: 0.14em;
  text-transform: uppercase;
}

.card-16__hint {
  align-self: flex-end;
  font-size: 9.5px;
  color: rgba(148, 163, 184, 0.6);
  letter-spacing: 0.14em;
  text-transform: uppercase;
}

.card-16__backbrand {
  font-family: Georgia, 'Times New Roman', serif;
  font-size: 10.5px;
  font-weight: 600;
  letter-spacing: 0.28em;
  color: rgba(212, 176, 99, 0.75);
  text-transform: uppercase;
}

.card-16__contact {
  font-style: normal;
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.card-16__row {
  display: flex;
  align-items: center;
  gap: 12px;
  min-height: 44px;
  padding-top: 4px;
  padding-bottom: 4px;
  border-bottom: 1px solid rgba(212, 176, 99, 0.14);
}

.card-16__row:last-child {
  border-bottom: 0;
}

.card-16__ico {
  color: var(--gold);
  flex-shrink: 0;
}

.card-16__row a {
  color: #e2e8f0;
  text-decoration: none;
  font-size: 13px;
  font-weight: 500;
  letter-spacing: 0.01em;
  transition: color 0.18s;
}

.card-16__row a:hover {
  color: var(--gold-lite);
}

.card-16__row a:focus-visible {
  outline: 2px solid var(--focus);
  outline-offset: 2px;
  border-radius: 3px;
}

@media (prefers-reduced-motion: reduce) {
  .card-16__inner {
    transition: none;
  }

  .card-16__card:hover .card-16__inner,
    .card-16__card:focus-within .card-16__inner {
    transform: none;
  }
}
Paste this into ChatGPT, Claude, Cursor, or any coding assistant. The block below is pre-framed with everything the AI needs to integrate this demo into your project — markup, styles, scoping notes, and the source URL. Hit Copy and paste straight into your chat.
Here's a working CSS Card from CodeFronts. Use it as-is or adapt to your framework. All classes are scoped under a unique prefix so the code won't collide with your existing styles. MIT licensed.
Demo: 3D Flip Business Card
Source: https://codefronts.com/components/css-cards/3d-flip-business-card/

Landscape business card that flips on hover AND focus-within (keyboard-accessible). Front shows avatar + name, back shows email/phone/site links. Reduced-motion disables the flip.
## HTML
```html
<section class="card-16">
  <div class="card-16__card" tabindex="0" aria-label="Business card for Alex Chen — flip to see contact details">
    <div class="card-16__inner">
      <div class="card-16__face card-16__front">
        <div class="card-16__brand" aria-hidden="true">
          <span class="card-16__mark"></span>
          <span class="card-16__brandname">CHEN &amp; CO</span>
        </div>
        <div class="card-16__id">
          <h3 class="card-16__name">Alex Chen</h3>
          <p class="card-16__role">Principal Designer</p>
        </div>
        <span class="card-16__hint">Hover to flip</span>
      </div>
      <div class="card-16__face card-16__back">
        <span class="card-16__backbrand">CHEN &amp; CO</span>
        <address class="card-16__contact">
          <div class="card-16__row">
            <svg class="card-16__ico" aria-hidden="true" focusable="false" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M4 4h16c1.1 0 2 .9 2 2v12c0 1.1-.9 2-2 2H4c-1.1 0-2-.9-2-2V6c0-1.1.9-2 2-2z"/><polyline points="22,6 12,13 2,6"/></svg>
            <a href="mailto:alex@chen.co">alex@chen.co</a>
          </div>
          <div class="card-16__row">
            <svg class="card-16__ico" aria-hidden="true" focusable="false" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M22 16.92v3a2 2 0 0 1-2.18 2 19.79 19.79 0 0 1-8.63-3.07 19.5 19.5 0 0 1-6-6 19.79 19.79 0 0 1-3.07-8.67A2 2 0 0 1 4.11 2h3a2 2 0 0 1 2 1.72 12.84 12.84 0 0 0 .7 2.81 2 2 0 0 1-.45 2.11L8.09 9.91a16 16 0 0 0 6 6l1.27-1.27a2 2 0 0 1 2.11-.45 12.84 12.84 0 0 0 2.81.7A2 2 0 0 1 22 16.92z"/></svg>
            <a href="tel:+14155550142">+1 (415) 555-0142</a>
          </div>
          <div class="card-16__row">
            <svg class="card-16__ico" aria-hidden="true" focusable="false" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><line x1="2" y1="12" x2="22" y2="12"/><path d="M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z"/></svg>
            <a href="#site">alexchen.design</a>
          </div>
        </address>
      </div>
    </div>
  </div>
</section>
```
## CSS
```css
.card-16 {
  width: 100%;
  min-height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: clamp(28px, 5vw, 56px) clamp(20px, 4vw, 40px);
  box-sizing: border-box;
  background: radial-gradient(ellipse at 30% 20%, #1e293b 0%, transparent 60%), radial-gradient(ellipse at 80% 80%, #0f172a 0%, transparent 60%), #050815;
  font-family: 'Inter', system-ui, sans-serif;
  --focus: #f5d97b;
  --gold: #d4b063;
  --gold-lite: #f5d97b;
}

.card-16 *,
.card-16 *::before,
.card-16 *::after {
  box-sizing: border-box;
}

.card-16__card {
  width: 360px;
  height: 220px;
  perspective: 1000px;
  border-radius: 14px;
}

.card-16__card:focus-visible {
  outline: 2px solid var(--focus);
  outline-offset: 6px;
  border-radius: 14px;
}

.card-16__inner {
  position: relative;
  width: 100%;
  height: 100%;
  transform-style: preserve-3d;
  transition: transform 0.7s cubic-bezier(0.34, 1.2, 0.64, 1);
  box-shadow: 0 30px 60px -12px rgba(0, 0, 0, 0.6), 0 18px 36px -18px rgba(212, 176, 99, 0.35);
}

.card-16__card:hover .card-16__inner,
.card-16__card:focus-within .card-16__inner {
  transform: rotateY(180deg);
}

.card-16__face {
  position: absolute;
  inset: 0;
  -webkit-backface-visibility: hidden;
  backface-visibility: hidden;
  border-radius: 14px;
  padding: 26px 28px;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  background: linear-gradient(135deg, rgba(212, 176, 99, 0.14) 0%, transparent 40%, transparent 60%, rgba(212, 176, 99, 0.06) 100%), linear-gradient(160deg, #16213e 0%, #0f172a 50%, #050815 100%);
  border: 1px solid rgba(212, 176, 99, 0.28);
}

.card-16__face::before {
  content: '';
  position: absolute;
  top: 0;
  right: 0;
  width: 60%;
  height: 60%;
  background: radial-gradient(circle at top right, rgba(245, 217, 123, 0.18), transparent 60%);
  pointer-events: none;
}

.card-16__front {
  justify-content: space-between;
}

.card-16__back {
  transform: rotateY(180deg);
  justify-content: space-between;
}

.card-16__brand {
  display: flex;
  align-items: center;
  gap: 10px;
}

.card-16__mark {
  width: 32px;
  height: 32px;
  border-radius: 50%;
  background: linear-gradient(135deg, #f5d97b 0%, #d4b063 50%, #9a7a3d 100%);
  box-shadow: inset 0 -2px 4px rgba(0, 0, 0, 0.25), inset 0 2px 4px rgba(255, 255, 255, 0.3), 0 2px 6px rgba(212, 176, 99, 0.35);
  position: relative;
}

.card-16__mark::before {
  content: '';
  position: absolute;
  inset: 8px;
  border-radius: 50%;
  background: linear-gradient(135deg, #050815, #16213e);
}

.card-16__mark::after {
  content: 'A';
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: Georgia, 'Times New Roman', serif;
  font-size: 15px;
  font-weight: 700;
  color: #f5d97b;
  text-shadow: 0 1px 2px rgba(0,0,0,0.6);
}

.card-16__brandname {
  font-family: Georgia, 'Times New Roman', serif;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.24em;
  color: var(--gold);
  text-transform: uppercase;
}

.card-16__id {
  margin-bottom: 12px;
}

.card-16__name {
  font-family: Georgia, 'Times New Roman', serif;
  font-size: 26px;
  font-weight: 700;
  margin: 0 0 4px;
  color: #f8fafc;
  letter-spacing: -0.005em;
  line-height: 1.1;
}

.card-16__role {
  font-size: 11px;
  font-weight: 500;
  color: rgba(245, 217, 123, 0.85);
  margin: 0;
  letter-spacing: 0.14em;
  text-transform: uppercase;
}

.card-16__hint {
  align-self: flex-end;
  font-size: 9.5px;
  color: rgba(148, 163, 184, 0.6);
  letter-spacing: 0.14em;
  text-transform: uppercase;
}

.card-16__backbrand {
  font-family: Georgia, 'Times New Roman', serif;
  font-size: 10.5px;
  font-weight: 600;
  letter-spacing: 0.28em;
  color: rgba(212, 176, 99, 0.75);
  text-transform: uppercase;
}

.card-16__contact {
  font-style: normal;
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.card-16__row {
  display: flex;
  align-items: center;
  gap: 12px;
  min-height: 44px;
  padding-top: 4px;
  padding-bottom: 4px;
  border-bottom: 1px solid rgba(212, 176, 99, 0.14);
}

.card-16__row:last-child {
  border-bottom: 0;
}

.card-16__ico {
  color: var(--gold);
  flex-shrink: 0;
}

.card-16__row a {
  color: #e2e8f0;
  text-decoration: none;
  font-size: 13px;
  font-weight: 500;
  letter-spacing: 0.01em;
  transition: color 0.18s;
}

.card-16__row a:hover {
  color: var(--gold-lite);
}

.card-16__row a:focus-visible {
  outline: 2px solid var(--focus);
  outline-offset: 2px;
  border-radius: 3px;
}

@media (prefers-reduced-motion: reduce) {
  .card-16__inner {
    transition: none;
  }

  .card-16__card:hover .card-16__inner,
    .card-16__card:focus-within .card-16__inner {
    transform: none;
  }
}
```

How this works

The card is a landscape 360×220px panel wrapped in a container flipped via transform-style: preserve-3d and a rotateY(180deg) swap on :hover, :focus-within, and [data-flipped='true']. The face renders a hand-coded navy gradient (#0b1220 to #1a2544) topped with a gilt monogram medallion — a 44px circle filled with a radial #f4d47c-to-#8a6a2c gradient, embossed initials, and a 1px solid rgba(244,212,124,0.55) ring. The brand mark reads CHEN & CO in a letter-spacing: 0.24em gilt caps rule set at 10px.

The back face lives at transform: rotateY(180deg) with backface-visibility: hidden applied to both faces. Contact rows use a grid-template-columns: 14px 1fr layout so each icon glyph and its value line share a baseline. Gold hairline dividers between rows are border-block-end: 1px solid rgba(244,212,124,0.18) — thin enough to read as engraved rather than printed. All colour tokens (--card-navy, --card-gilt, --card-gilt-soft) are scoped under .xx-16 so nothing bleeds into a host design system.

Motion is GPU-accelerated by keeping the transform on the wrapper only and running it through transition: transform 720ms cubic-bezier(0.22, 1, 0.36, 1). A @media (prefers-reduced-motion: reduce) block drops the flip duration to 1ms and replaces the rotation with an opacity crossfade so vestibular-sensitive users still see the back face without spatial motion. The whole component is SSR-safe and React/Vue/Next-compatible because it ships zero JavaScript — the flip is :focus-within-driven, which means tabbing to any interactive element on either face triggers it without a state hook.

Make it yours

  • Retint the navy face by editing --card-navy and --card-navy-lift — try slate (#0f172a to #22304d) for a fintech register, or espresso (#1c1410 to #33241a) for a hospitality feel. Contrast against gilt stays WCAG AA at every step.
  • Swap the monogram medallion for a mark by replacing the initials span with an inline SVG logo sized 28×28px. Keep the rgba(244,212,124,0.55) ring — it reads as etched metal against dark faces and prevents the mark from looking pasted on.
  • Change orientation to portrait by flipping the wrapper to 220×360px and shifting the back-face grid to a single column. The flip axis reads more like a passport than a card, which suits founder profiles and speaker-badge use cases.
  • Retune the flip feel via transition-duration and cubic-bezier520ms with (0.4, 0, 0.2, 1) reads snappier for dense dashboards, while 900ms with (0.16, 1, 0.3, 1) reads more ceremonial for premium landing surfaces.
  • Add a hairline gilt border to the whole card with box-shadow: 0 0 0 1px rgba(244,212,124,0.22) inset. Pair with a filter: drop-shadow(0 24px 32px rgba(8,12,24,0.45)) on the wrapper for a floating-on-felt look on cream or ivory hero sections.

Gotchas — read before shipping

  • Both faces need backface-visibility: hidden AND -webkit-backface-visibility: hidden — Safari on iOS 16 and older still needs the vendor prefix or the reversed face shows through as a mirrored ghost during the flip, which reads as a rendering bug on premium surfaces.
  • The :focus-within flip is the accessibility path — never gate the reveal behind hover only, or keyboard users tabbing to the contact links on the back face will be trapped facing a hidden panel. WCAG 2.1.1 and 2.4.7 both require the reversed side to be reachable without a pointer.
  • Contact links on the back face must clear the 44×44px WCAG 2.5.5 target size. The gilt hairline rows tempt tight 32px row heights — pad each anchor with padding-block: 12px so the tap surface exceeds spec even when the visible glyph is smaller.
  • The gilt gradient (#f4d47c on #0b1220) hits a 10.8:1 contrast ratio at 10px caps, but tightening letter-spacing below 0.18em collapses stroke gaps and drops legibility for low-vision users below WCAG 1.4.3 in practice — keep the tracking loose.
  • Serve @media (prefers-reduced-motion: reduce) as a crossfade, not a hard cut — WCAG 2.3.3 asks for reduced motion, not zero feedback. A 200ms opacity swap between faces preserves the mental model of a two-sided card without triggering vestibular symptoms.
  • The flip transform promotes the wrapper to its own compositor layer, which is INP-safe on the interaction but expensive if you stack fifty of these on a directory page. Add content-visibility: auto and contain-intrinsic-size: 220px 360px to off-screen cards or scroll jank spikes above the 200ms INP threshold.

Techniques used in this demo

Search CodeFronts

Loading…