カードフリップ(3D反転)実装解説|Card Flip

カードフリップ デザイン見本

perspective と rotateY / rotateX を組み合わせた 3D カード反転の実装デモ。コピーしてすぐに使える HTML・CSS・JS のコードを掲載。

① ホバーでフリップ(CSSのみ)

HOVER ME

Back Side

hover を外すと戻ります

カードにホバーしてください

HTML
<div class="card-wrapper">
  <div class="card">
    <div class="front">
      <p>HOVER ME</p>
    </div>
    <div class="back">
      <p>Back Side</p>
    </div>
  </div>
</div>
CSS
.card-wrapper {
  perspective: 800px;
  width: 180px;
  height: 240px;
}
.card {
  width: 100%;
  height: 100%;
  position: relative;
  transform-style: preserve-3d;
  transition: transform 0.6s ease;
}
.card-wrapper:hover .card {
  transform: rotateY(180deg);
}
.front,
.back {
  backface-visibility: hidden;
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  border-radius: 12px;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  text-align: center;
  padding: 20px;
  box-sizing: border-box;
}
.front {
  background: linear-gradient(135deg, #667eea, #764ba2);
  color: #fff;
}
.back {
  transform: rotateY(180deg);
  background: #fff;
  color: #333;
  border: 2px solid #e2e8f0;
}
perspective / transform-style: preserve-3d / backface-visibility: hidden

親要素に perspective を設定して 3D 空間の奥行感を生み出す。カード本体に transform-style: preserve-3d を付けると子要素も 3D 空間に配置される。裏面には rotateY(180deg) を初期値として付けておき、backface-visibility: hidden で裏側を透明にすることで自然な反転が実現できる。

② クリックでフリップ(JS 制御)

現在: 表面

CLICK ME

Back Side

もう一度クリックで戻る

HTML
<div class="card-wrapper">
  <div class="card">
    <div class="front">
      <p>CLICK ME</p>
    </div>
    <div class="back">
      <p>Back Side</p>
    </div>
  </div>
</div>
<button class="flip-btn">フリップ</button>
CSS
.card-wrapper {
  perspective: 800px;
  width: 180px;
  height: 240px;
}
.card {
  width: 100%;
  height: 100%;
  position: relative;
  transform-style: preserve-3d;
  transition: transform 0.6s ease;
}
.card.flipped {
  transform: rotateY(180deg);
}
.front,
.back {
  backface-visibility: hidden;
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  border-radius: 12px;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  text-align: center;
  padding: 20px;
  box-sizing: border-box;
}
.front {
  background: linear-gradient(135deg, #06b6d4, #0891b2);
  color: #fff;
}
.back {
  transform: rotateY(180deg);
  background: #f0fdfa;
  color: #164e63;
  border: 2px solid #a5f3fc;
}
.flip-btn {
  margin-top: 16px;
  padding: 8px 24px;
  border-radius: 20px;
  border: 1px solid #06b6d4;
  background: #ecfeff;
  color: #0e7490;
  font-weight: 600;
  cursor: pointer;
}
JS
(function() {
  var card = document.querySelector('.card');
  var btn = document.querySelector('.flip-btn');
  if (!card || !btn) return;
  btn.addEventListener('click', function() {
    var flipped = card.className.indexOf('flipped') !== -1;
    if (flipped) {
      card.className = 'card';
    } else {
      card.className = 'card flipped';
    }
  });
})();
.flipped クラスの付け外し

CSS で .card.flipped { transform: rotateY(180deg); } を定義しておき、JS ではクラスを付け外しするだけでフリップを制御できる。className.indexOf(‘flipped’) で現在の状態を判定し、あれば外す・なければ付けるというシンプルなトグルで実装できる。

③ 縦方向フリップ(rotateX)

現在: 表面

CLICK ME

Back Side

rotateX で縦転する

HTML
<div class="card-wrapper">
  <div class="card">
    <div class="front">
      <p>CLICK ME</p>
    </div>
    <div class="back">
      <p>Back Side</p>
    </div>
  </div>
</div>
<button class="flip-btn">フリップ</button>
CSS
.card-wrapper {
  perspective: 800px;
  width: 180px;
  height: 240px;
}
.card {
  width: 100%;
  height: 100%;
  position: relative;
  transform-style: preserve-3d;
  transition: transform 0.6s ease;
}
.card.flipped {
  transform: rotateX(180deg);
}
.front,
.back {
  backface-visibility: hidden;
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  border-radius: 12px;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  text-align: center;
  padding: 20px;
  box-sizing: border-box;
}
.front {
  background: linear-gradient(135deg, #f59e0b, #d97706);
  color: #fff;
}
.back {
  transform: rotateX(180deg);
  background: #fffbeb;
  color: #78350f;
  border: 2px solid #fde68a;
}
.flip-btn {
  margin-top: 16px;
  padding: 8px 24px;
  border-radius: 20px;
  border: 1px solid #f59e0b;
  background: #fffbeb;
  color: #92400e;
  font-weight: 600;
  cursor: pointer;
}
JS
(function() {
  var card = document.querySelector('.card');
  var btn = document.querySelector('.flip-btn');
  if (!card || !btn) return;
  btn.addEventListener('click', function() {
    var flipped = card.className.indexOf('flipped') !== -1;
    if (flipped) {
      card.className = 'card';
    } else {
      card.className = 'card flipped';
    }
  });
})();
rotateY と rotateX の違い

rotateY(180deg) は縦の軸を中心に横方向へ回転(本のページをめくるような動き)。rotateX(180deg) は横の軸を中心に縦方向へ回転(扉が上下に開くような動き)。裏面の初期値も同じ軸で rotateX(180deg) を設定する必要がある点に注意。

④ グループ排他制御(1枚だけ開く)

カードをクリックしてください

Card 1

Back 1

Star

Card 2

Back 2

Sun

Card 3

Back 3

Diamond

HTML
<div class="card-group">
  <div class="card-wrapper">
    <div class="card">
      <div class="front"><p>Card 1</p></div>
      <div class="back"><p>Back 1</p></div>
    </div>
  </div>
  <div class="card-wrapper">
    <div class="card">
      <div class="front"><p>Card 2</p></div>
      <div class="back"><p>Back 2</p></div>
    </div>
  </div>
  <div class="card-wrapper">
    <div class="card">
      <div class="front"><p>Card 3</p></div>
      <div class="back"><p>Back 3</p></div>
    </div>
  </div>
</div>
CSS
.card-group {
  display: flex;
  gap: 16px;
  justify-content: center;
  flex-wrap: wrap;
}
.card-wrapper {
  perspective: 600px;
  width: 140px;
  height: 200px;
  cursor: pointer;
}
.card {
  width: 100%;
  height: 100%;
  position: relative;
  transform-style: preserve-3d;
  transition: transform 0.6s ease;
}
.card.flipped {
  transform: rotateY(180deg);
}
.front,
.back {
  backface-visibility: hidden;
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  border-radius: 12px;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  text-align: center;
  padding: 16px;
  box-sizing: border-box;
}
.back {
  transform: rotateY(180deg);
  background: #f8fafc;
  color: #334155;
  border: 2px solid #e2e8f0;
}
JS
(function() {
  var wrappers = document.querySelectorAll('.card-wrapper');
  wrappers.forEach(function(wrapper) {
    wrapper.addEventListener('click', function() {
      var card = wrapper.querySelector('.card');
      if (!card) return;
      var nowFlipped = card.className.indexOf('flipped') !== -1;
      wrappers.forEach(function(w) {
        var c = w.querySelector('.card');
        if (c) c.className = 'card';
      });
      if (!nowFlipped) {
        card.className = 'card flipped';
      }
    });
  });
})();
排他制御パターン

「全閉じ → 対象だけ開く」という 2 ステップで排他制御を実現する。まずすべてのカードから flipped クラスを外し、その後クリックされたカードが開いていなかった場合のみ flipped を付与する。すでに開いていた場合はそのまま閉じた状態になる。


当サイトで公開しているWebデザインやUIの実装例は、一覧として以下記事に纏めています。

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!
目次