ホログラフィックカード(3Dティルト)Holographic Card
.cg-in-holo {
perspective: 800px;
padding: 16px;
}
.cg-in-holo .card {
--px: .5; --py: .5; --mx: 50%; --my: 50%; --d: 0;
position: relative;
width: 178px;
height: 248px;
border-radius: 16px;
overflow: hidden;
background: linear-gradient(160deg, #202B4A, #0A0E1C);
box-shadow:
0 18px 40px rgba(0, 0, 0, .5),
0 2px 8px rgba(0, 0, 0, .4);
transform: rotateX(calc((var(--py) - .5) * -24deg)) rotateY(calc((var(--px) - .5) * 24deg));
transition: transform .12s ease-out;
transform-style: preserve-3d;
}
/* ① ベースの下地シャイン(斜めに走る白光) */
.cg-in-holo .shine {
position: absolute;
inset: 0;
background: linear-gradient(105deg, transparent 30%, rgba(255,255,255,.14) 48%, transparent 62%);
background-size: 220% 220%;
background-position: calc(var(--mx) * 1.4) calc(var(--my) * 1.4);
pointer-events: none;
}
/* ② 主ホログラム箔: 虹色ストライプ。マウスで移動 */
.cg-in-holo .foil {
position: absolute;
inset: 0;
background: repeating-linear-gradient(115deg,
#FF5EA8 0%, #FFD86B 12%, #66FFB2 24%, #5EC8FF 36%, #C46BFF 48%, #FF5EA8 60%);
background-size: 260% 260%;
background-position: var(--mx) var(--my);
mix-blend-mode: color-dodge;
opacity: calc(.28 + var(--d) * .5);
pointer-events: none;
}
/* ③ 逆位相の第2箔: 角度で虹が振動して奥行きが出る */
.cg-in-holo .foil2 {
position: absolute;
inset: 0;
background: repeating-linear-gradient(-70deg,
#7CF9FF 0%, #B98CFF 20%, #FF8FD0 40%, #FFE58A 60%, #7CF9FF 80%);
background-size: 300% 300%;
background-position: calc(100% - var(--mx)) calc(100% - var(--my));
mix-blend-mode: overlay;
opacity: calc(.18 + var(--d) * .35);
pointer-events: none;
}
/* ④ きらめくスパークル粒子(SVGノイズをマスク) */
.cg-in-holo .sparkle {
position: absolute;
inset: 0;
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='120' height='120'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.9' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='120' height='120' filter='url(%23n)'/%3E%3C/svg%3E");
background-size: 130px 130px;
mix-blend-mode: color-dodge;
opacity: calc(var(--d) * .6);
-webkit-mask: radial-gradient(circle 90px at var(--mx) var(--my), #000 10%, transparent 60%);
mask: radial-gradient(circle 90px at var(--mx) var(--my), #000 10%, transparent 60%);
pointer-events: none;
}
/* ⑤ カーソル直下の白い強光沢 */
.cg-in-holo .glare {
position: absolute;
inset: 0;
background: radial-gradient(circle 100px at var(--mx) var(--my), rgba(255,255,255,.65), transparent 55%);
mix-blend-mode: overlay;
opacity: calc(.4 + var(--d) * .6);
pointer-events: none;
}
/* ⑥ 傾けた側が発光するエッジライト */
.cg-in-holo .edge {
position: absolute;
inset: 0;
border-radius: 16px;
box-shadow: inset 0 0 0 1.5px rgba(150,190,255,.35);
background: linear-gradient(var(--mx), rgba(120,180,255,.0), rgba(120,180,255,.0));
pointer-events: none;
}
.cg-in-holo .card::after {
content: "";
position: absolute;
inset: 0;
border-radius: 16px;
box-shadow: inset calc((var(--px) - .5) * -20px) calc((var(--py) - .5) * -20px) 30px rgba(130,180,255,.4);
pointer-events: none;
}
.cg-in-holo .face {
position: absolute;
inset: 0;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: 6px;
color: #EAF0FF;
transform: translateZ(40px);
}
/* パララックス: 要素ごとに違う深度で動く */
.cg-in-holo b {
font-size: 24px;
font-weight: 900;
letter-spacing: .16em;
text-shadow: 0 2px 8px rgba(0,0,0,.5);
transform: translate(calc((var(--px) - .5) * 14px), calc((var(--py) - .5) * 14px));
}
.cg-in-holo small { font-size: 8.5px; letter-spacing: .22em; color: #93A8D0; }
.cg-in-holo .orb {
width: 58px;
height: 58px;
margin-top: 10px;
border-radius: 50%;
background: radial-gradient(circle at 34% 28%, #CFE0FF, #3A6FD8 52%, #0C1A3C);
box-shadow: 0 0 26px rgba(90,140,255,.75), inset 0 -6px 12px rgba(0,0,0,.4);
transform: translate(calc((var(--px) - .5) * 26px), calc((var(--py) - .5) * 26px));
}
.cg-in-holo em {
font-style: normal;
font-size: 9px;
font-weight: 900;
letter-spacing: .18em;
color: #FFD86B;
margin-top: 8px;
text-shadow: 0 0 8px rgba(255,216,107,.6);
}
/* reduced-motion: 傾き・箔移動を止め、静止した箔だけ薄く残す */
@media (prefers-reduced-motion: reduce) {
.cg-in-holo .card { transition: none; transform: none; }
.cg-in-holo .sparkle, .cg-in-holo .foil2 { opacity: .12; }
}
<div class="cg-in-holo"><div class="card"><span class="shine"></span><span class="foil"></span><span class="foil2"></span><span class="sparkle"></span><span class="glare"></span><span class="edge"></span><div class="face"><b>OCEAN</b><small>CSS CARGO · HOLO</small><i class="orb"></i><em>★ RARE ★</em></div></div></div>
(function () {
var wrap = document.querySelector('.cg-in-holo');
if (!wrap) return;
var card = wrap.querySelector('.card');
var reduce = window.matchMedia && window.matchMedia('(prefers-reduced-motion: reduce)');
/* rAFで目標値へ滑らかに追従(生のmousemoveより上質な動き) */
var tx = .5, ty = .5, x = .5, y = .5, td = 0, d = 0, raf = 0;
function apply() {
card.style.setProperty('--px', x);
card.style.setProperty('--py', y);
card.style.setProperty('--mx', (x * 100) + '%');
card.style.setProperty('--my', (y * 100) + '%');
card.style.setProperty('--d', d);
}
function loop() {
var k = .18;
x += (tx - x) * k; y += (ty - y) * k; d += (td - d) * k;
apply();
if (Math.abs(tx - x) > .001 || Math.abs(ty - y) > .001 || Math.abs(td - d) > .001) {
raf = requestAnimationFrame(loop);
} else { raf = 0; }
}
function kick() { if (!raf) raf = requestAnimationFrame(loop); }
if (reduce && reduce.matches) return;
wrap.addEventListener('pointermove', function (e) {
var r = card.getBoundingClientRect();
tx = Math.max(0, Math.min(1, (e.clientX - r.left) / r.width));
ty = Math.max(0, Math.min(1, (e.clientY - r.top) / r.height));
td = 1; /* ホバー中は箔・スパークルを強める */
kick();
});
wrap.addEventListener('pointerleave', function () {
tx = .5; ty = .5; td = 0; /* 正面へ戻り、箔が鎮まる */
kick();
});
})();