3Dティルトカード
マウス位置を回転角に変換し、CSSのperspectiveでカードが立体的に傾き光沢が走ります。商品カードやプロフィールカードの演出に最適です。
ライブデモ
使用例(お題: アイドルグループ Sakura)
この技法を「アイドルグループ Sakura」というテーマのダミーサイトで実際に使った例です。
HTML
<!-- Sakura: メンバー紹介。3Dティルトカードを主役に -->
<div class="sk">
<header class="sk__head">
<span class="sk__logo">🌸 Sakura</span>
<span class="sk__sub">MEMBER</span>
</header>
<div class="sk__stage">
<div class="tilt" tabindex="0">
<div class="tilt__inner">
<div class="tilt__photo">
<img src="https://picsum.photos/300/300?random=41" alt="メンバーのプロフィール写真" loading="lazy">
<span class="tilt__color">PINK</span>
</div>
<div class="tilt__info">
<p class="tilt__role">センター / リーダー</p>
<h1 class="tilt__name">星野 ひより</h1>
<p class="tilt__msg">「今日も全力でお届けします!」</p>
<div class="tilt__tags"><span>歌</span><span>ダンス</span><span>春生まれ</span></div>
</div>
<span class="tilt__glare" aria-hidden="true"></span>
</div>
</div>
<p class="sk__hint">カードにカーソルを乗せると立体的に傾きます</p>
</div>
</div>
CSS
/* Sakura アイドル テーマ: 桜ピンク/白/淡グレー */
* { box-sizing: border-box; }
body {
margin: 0;
font-family: "Hiragino Kaku Gothic ProN", "Segoe UI", system-ui, sans-serif;
background:
radial-gradient(circle at 80% 15%, #ffe3ee 0%, transparent 50%),
radial-gradient(circle at 15% 85%, #ffd1e0 0%, transparent 45%),
#fff7fb;
color: #6b4a58;
}
.sk {
height: 400px;
display: flex;
flex-direction: column;
padding: 0 28px;
}
.sk__head {
display: flex;
align-items: baseline;
gap: 14px;
padding: 18px 0;
}
.sk__logo {
font-size: 18px;
font-weight: 800;
color: #e85a92;
}
.sk__sub {
font-size: 12px;
letter-spacing: .24em;
color: #c79bb0;
}
.sk__stage {
flex: 1;
display: grid;
place-content: center;
gap: 16px;
perspective: 900px;
}
/* 主役: 3Dティルトカード */
.tilt {
--rx: 0deg;
--ry: 0deg;
--mx: 50%;
--my: 50%;
width: 320px;
border-radius: 20px;
outline: none;
cursor: pointer;
}
.tilt__inner {
position: relative;
display: flex;
gap: 14px;
padding: 14px;
border-radius: 20px;
background: #ffffff;
box-shadow: 0 22px 44px rgba(232,90,146,.28);
transform: rotateX(var(--rx)) rotateY(var(--ry));
transform-style: preserve-3d;
transition: transform .2s ease;
overflow: hidden;
}
.tilt__photo {
position: relative;
width: 110px;
height: 130px;
flex: none;
border-radius: 14px;
overflow: hidden;
}
.tilt__photo img {
width: 100%;
height: 100%;
object-fit: cover;
display: block;
}
.tilt__color {
position: absolute;
left: 8px;
bottom: 8px;
font-size: 10px;
font-weight: 800;
letter-spacing: .1em;
color: #fff;
background: #e85a92;
padding: 3px 8px;
border-radius: 999px;
}
.tilt__info {
display: flex;
flex-direction: column;
justify-content: center;
gap: 4px;
}
.tilt__role {
margin: 0;
font-size: 11px;
font-weight: 700;
color: #e85a92;
}
.tilt__name {
margin: 2px 0;
font-size: 22px;
font-weight: 800;
color: #4a3340;
}
.tilt__msg {
margin: 0;
font-size: 12px;
color: #9a7d8a;
}
.tilt__tags {
display: flex;
gap: 6px;
margin-top: 6px;
}
.tilt__tags span {
font-size: 10px;
color: #b56685;
background: #ffeaf2;
padding: 3px 9px;
border-radius: 999px;
}
/* マウス位置に追従する光沢 */
.tilt__glare {
position: absolute;
inset: 0;
pointer-events: none;
background: radial-gradient(
circle at var(--mx) var(--my),
rgba(255,255,255,.55) 0%, rgba(255,255,255,0) 45%);
mix-blend-mode: screen;
}
.sk__hint {
margin: 0;
text-align: center;
font-size: 11px;
color: #c79bb0;
}
@media (prefers-reduced-motion: reduce) {
.tilt__inner { transform: none !important; transition: none; }
.tilt__glare { display: none; }
}
JavaScript
// Sakuraメンバーカード: ポインタ位置を回転角へ変換して立体的に傾ける
(() => {
const card = document.querySelector('.tilt');
if (!card) return; // null安全
const reduce = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
if (reduce) return;
const MAX = 12; // 最大傾き(deg)
const update = (clientX, clientY) => {
const r = card.getBoundingClientRect();
const px = (clientX - r.left) / r.width; // 0..1
const py = (clientY - r.top) / r.height; // 0..1
// 中央を基準に符号付き角度を算出
card.style.setProperty('--ry', `${(px - 0.5) * 2 * MAX}deg`);
card.style.setProperty('--rx', `${(0.5 - py) * 2 * MAX}deg`);
// 光沢の中心も同期
card.style.setProperty('--mx', `${px * 100}%`);
card.style.setProperty('--my', `${py * 100}%`);
};
card.addEventListener('pointermove', (e) => update(e.clientX, e.clientY));
// 離脱時は水平に戻す
const reset = () => {
card.style.setProperty('--rx', '0deg');
card.style.setProperty('--ry', '0deg');
card.style.setProperty('--mx', '50%');
card.style.setProperty('--my', '50%');
};
card.addEventListener('pointerleave', reset);
card.addEventListener('blur', reset);
})();
コード
HTML
<!-- 3Dティルトカード: マウス位置で立体的に傾く -->
<div class="stage">
<article class="tilt" tabindex="0">
<div class="tilt__shine" aria-hidden="true"></div>
<div class="tilt__content">
<span class="tilt__badge">PREMIUM</span>
<h2 class="tilt__title">Aurora Pass</h2>
<p class="tilt__desc">傾けると光沢が走る、奥行きのあるカード。</p>
<div class="tilt__foot">
<span class="tilt__num">**** 4271</span>
<span class="tilt__chip" aria-hidden="true"></span>
</div>
</div>
</article>
</div>
CSS
* { box-sizing: border-box; }
body {
margin: 0;
min-height: 100vh;
display: grid;
place-items: center;
font-family: "Segoe UI", system-ui, sans-serif;
background: radial-gradient(circle at 50% 30%, #1b2735 0%, #090a0f 70%);
}
/* 親に遠近感を与える */
.stage {
perspective: 900px;
}
/* カード本体: CSS変数で回転角を受け取る */
.tilt {
--rx: 0deg;
--ry: 0deg;
--mx: 50%;
--my: 50%;
position: relative;
width: 300px;
height: 188px;
border-radius: 18px;
padding: 22px;
cursor: pointer;
transform: rotateX(var(--rx)) rotateY(var(--ry));
transform-style: preserve-3d;
transition: transform .25s ease;
background: linear-gradient(135deg, #5b2bff 0%, #b829e3 50%, #ff5e9c 100%);
box-shadow: 0 30px 60px rgba(91, 43, 255, .35);
color: #fff;
outline: none;
overflow: hidden;
}
.tilt:focus-visible {
box-shadow: 0 0 0 3px #fff, 0 30px 60px rgba(91, 43, 255, .45);
}
/* マウス追従のハイライト */
.tilt__shine {
position: absolute;
inset: 0;
background: radial-gradient(
circle at var(--mx) var(--my),
rgba(255, 255, 255, .55) 0%,
rgba(255, 255, 255, 0) 45%
);
mix-blend-mode: soft-light;
pointer-events: none;
}
/* 中身を手前に浮かせる */
.tilt__content {
position: relative;
height: 100%;
display: flex;
flex-direction: column;
transform: translateZ(40px);
}
.tilt__badge {
align-self: flex-start;
font-size: 11px;
font-weight: 700;
letter-spacing: .18em;
padding: 4px 10px;
border-radius: 999px;
background: rgba(255, 255, 255, .22);
backdrop-filter: blur(4px);
}
.tilt__title {
margin: 14px 0 4px;
font-size: 26px;
letter-spacing: .01em;
}
.tilt__desc {
margin: 0;
font-size: 12.5px;
line-height: 1.5;
color: rgba(255, 255, 255, .85);
}
.tilt__foot {
margin-top: auto;
display: flex;
align-items: center;
justify-content: space-between;
}
.tilt__num {
font-family: ui-monospace, "Courier New", monospace;
letter-spacing: .12em;
font-size: 15px;
}
/* ICチップ風の装飾 */
.tilt__chip {
width: 38px;
height: 27px;
border-radius: 6px;
background: linear-gradient(135deg, #ffe7a0, #d9a441);
box-shadow: inset 0 0 0 1px rgba(0, 0, 0, .2);
}
@media (prefers-reduced-motion: reduce) {
.tilt { transition: none; transform: none !important; }
.tilt__shine { display: none; }
}
JavaScript
// 3Dティルトカード: カード内のポインタ位置を -0.5..0.5 に正規化して回転へ変換
(() => {
const card = document.querySelector('.tilt');
if (!card) return; // null安全
const reduce = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
if (reduce) return;
const MAX = 14; // 最大傾き(deg)
const update = (clientX, clientY) => {
const r = card.getBoundingClientRect();
const px = (clientX - r.left) / r.width; // 0..1
const py = (clientY - r.top) / r.height; // 0..1
// 中央を基準に符号付き角度を算出
card.style.setProperty('--ry', `${(px - 0.5) * 2 * MAX}deg`);
card.style.setProperty('--rx', `${(0.5 - py) * 2 * MAX}deg`);
// 光沢の中心も同期
card.style.setProperty('--mx', `${px * 100}%`);
card.style.setProperty('--my', `${py * 100}%`);
};
card.addEventListener('pointermove', (e) => update(e.clientX, e.clientY));
// 離脱時は水平に戻す
const reset = () => {
card.style.setProperty('--rx', '0deg');
card.style.setProperty('--ry', '0deg');
card.style.setProperty('--mx', '50%');
card.style.setProperty('--my', '50%');
};
card.addEventListener('pointerleave', reset);
card.addEventListener('blur', reset);
})();
🤖 AIエージェント用プロンプト
このままコピーしてAIに貼り付け「追加する場所」だけ書き換えればOK
あなたは熟練のフロントエンドエンジニアです。私のWebサイトに「3Dティルトカード」の効果を追加してください。
# 追加してほしい効果
3Dティルトカード(マイクロインタラクション)
マウス位置を回転角に変換し、CSSのperspectiveでカードが立体的に傾き光沢が走ります。商品カードやプロフィールカードの演出に最適です。
# 追加する場所
👉【ここに対象箇所を記入:例「トップのヒーローセクション」「お問い合わせボタン」「記事カードの一覧」など】
# 参考実装(この見た目・挙動を再現してください)
【HTML】
<!-- 3Dティルトカード: マウス位置で立体的に傾く -->
<div class="stage">
<article class="tilt" tabindex="0">
<div class="tilt__shine" aria-hidden="true"></div>
<div class="tilt__content">
<span class="tilt__badge">PREMIUM</span>
<h2 class="tilt__title">Aurora Pass</h2>
<p class="tilt__desc">傾けると光沢が走る、奥行きのあるカード。</p>
<div class="tilt__foot">
<span class="tilt__num">**** 4271</span>
<span class="tilt__chip" aria-hidden="true"></span>
</div>
</div>
</article>
</div>
【CSS】
* { box-sizing: border-box; }
body {
margin: 0;
min-height: 100vh;
display: grid;
place-items: center;
font-family: "Segoe UI", system-ui, sans-serif;
background: radial-gradient(circle at 50% 30%, #1b2735 0%, #090a0f 70%);
}
/* 親に遠近感を与える */
.stage {
perspective: 900px;
}
/* カード本体: CSS変数で回転角を受け取る */
.tilt {
--rx: 0deg;
--ry: 0deg;
--mx: 50%;
--my: 50%;
position: relative;
width: 300px;
height: 188px;
border-radius: 18px;
padding: 22px;
cursor: pointer;
transform: rotateX(var(--rx)) rotateY(var(--ry));
transform-style: preserve-3d;
transition: transform .25s ease;
background: linear-gradient(135deg, #5b2bff 0%, #b829e3 50%, #ff5e9c 100%);
box-shadow: 0 30px 60px rgba(91, 43, 255, .35);
color: #fff;
outline: none;
overflow: hidden;
}
.tilt:focus-visible {
box-shadow: 0 0 0 3px #fff, 0 30px 60px rgba(91, 43, 255, .45);
}
/* マウス追従のハイライト */
.tilt__shine {
position: absolute;
inset: 0;
background: radial-gradient(
circle at var(--mx) var(--my),
rgba(255, 255, 255, .55) 0%,
rgba(255, 255, 255, 0) 45%
);
mix-blend-mode: soft-light;
pointer-events: none;
}
/* 中身を手前に浮かせる */
.tilt__content {
position: relative;
height: 100%;
display: flex;
flex-direction: column;
transform: translateZ(40px);
}
.tilt__badge {
align-self: flex-start;
font-size: 11px;
font-weight: 700;
letter-spacing: .18em;
padding: 4px 10px;
border-radius: 999px;
background: rgba(255, 255, 255, .22);
backdrop-filter: blur(4px);
}
.tilt__title {
margin: 14px 0 4px;
font-size: 26px;
letter-spacing: .01em;
}
.tilt__desc {
margin: 0;
font-size: 12.5px;
line-height: 1.5;
color: rgba(255, 255, 255, .85);
}
.tilt__foot {
margin-top: auto;
display: flex;
align-items: center;
justify-content: space-between;
}
.tilt__num {
font-family: ui-monospace, "Courier New", monospace;
letter-spacing: .12em;
font-size: 15px;
}
/* ICチップ風の装飾 */
.tilt__chip {
width: 38px;
height: 27px;
border-radius: 6px;
background: linear-gradient(135deg, #ffe7a0, #d9a441);
box-shadow: inset 0 0 0 1px rgba(0, 0, 0, .2);
}
@media (prefers-reduced-motion: reduce) {
.tilt { transition: none; transform: none !important; }
.tilt__shine { display: none; }
}
【JavaScript】
// 3Dティルトカード: カード内のポインタ位置を -0.5..0.5 に正規化して回転へ変換
(() => {
const card = document.querySelector('.tilt');
if (!card) return; // null安全
const reduce = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
if (reduce) return;
const MAX = 14; // 最大傾き(deg)
const update = (clientX, clientY) => {
const r = card.getBoundingClientRect();
const px = (clientX - r.left) / r.width; // 0..1
const py = (clientY - r.top) / r.height; // 0..1
// 中央を基準に符号付き角度を算出
card.style.setProperty('--ry', `${(px - 0.5) * 2 * MAX}deg`);
card.style.setProperty('--rx', `${(0.5 - py) * 2 * MAX}deg`);
// 光沢の中心も同期
card.style.setProperty('--mx', `${px * 100}%`);
card.style.setProperty('--my', `${py * 100}%`);
};
card.addEventListener('pointermove', (e) => update(e.clientX, e.clientY));
// 離脱時は水平に戻す
const reset = () => {
card.style.setProperty('--rx', '0deg');
card.style.setProperty('--ry', '0deg');
card.style.setProperty('--mx', '50%');
card.style.setProperty('--my', '50%');
};
card.addEventListener('pointerleave', reset);
card.addEventListener('blur', reset);
})();
# 外部ライブラリ
なし(追加ライブラリ不要)
# 守ってほしいこと
- 既存のHTML構造・レイアウト・デザインを壊さないこと。必要に応じてクラス名・色・サイズを私のサイトに合わせて調整してよい。
- クラス名やidが既存と衝突しないよう、必要なら接頭辞で名前空間を分けること。
- レスポンシブ対応と prefers-reduced-motion への配慮を入れること。
- 私のサイトのフレームワーク(React / Vue / 素のHTML など)に合わせて実装すること。不明な場合は素のHTML/CSS/JSで提示し、組み込み手順も説明すること。
- 変更後の確認手順も簡潔に教えてください。