Bloggerに関するカスタマイズ・テンプレート・TIPSを紹介しています。

2026/02/27

Bloggerデザイン : 3Dホバーカード

デザインのタイプ

【3Dレイヤー・パララックス・ホバーカード】
複数の画像レイヤーとマウス追従エフェクトを組み合わせた、奥行きのあるインタラクティブなカードデザイン。キャラクターやオブジェクトがフレームから飛び出すような、ダイナミックな視覚体験を提供します。

Hover me!

3D Parallax Effect with CSS & JS.

Hover me!

Interactive depth and motion.

デザインの特徴

  • 多層レイヤー構造
    背景、カットアウト、装飾フレームを分離したレイヤーで構成し、物理的な奥行きを表現。
  • マウス追従3D回転
    カーソルの位置に連動してカードがリアルタイムに傾斜し、動的なインタラクションを提供。
  • 飛び出し演出
    特定のレイヤーをフレーム前方に配置することで、ホバー時にキャラクターが飛び出すような視覚効果を実現。

紹介コード

HTML・CSS JavaScript

<style>
/* --- CSS Area --- */
.tpd-3d-wrapper {
    width: 100%;
    padding: 50px 0;
    background: #111; /* 背景を見やすくするために暗転 */
    overflow: hidden;
}

.tpd-centered {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 2rem;
    flex-wrap: wrap; /* スマホ等で折り返し可能に */
}

.tpd-card {
    position: relative;
    height: 28rem;
    width: 20rem;
    color: #ffffff;
    perspective: 50rem;
    cursor: pointer;
}

.tpd-card .shadow {
    position: absolute;
    inset: 0;
    background: var(--url);
    background-size: cover;
    background-position: center;
    opacity: 0.8;
    filter: blur(2rem) saturate(0.9);
    box-shadow: 0 -1.5rem 2rem -0.5rem rgba(0, 0, 0, 0.7);
    transform: rotateX(var(--rotateX, 0deg)) rotateY(var(--rotateY, 0deg)) translate3d(0, 2rem, -2rem);
}

.tpd-card .image {
    position: absolute;
    inset: 0;
    background: linear-gradient(to top, rgba(0, 0, 0, 0.5), transparent 40%), var(--url);
    background-size: cover;
    background-position: center;
    -webkit-mask-image: var(--url);
    mask-image: var(--url);
    -webkit-mask-size: cover;
    mask-size: cover;
    -webkit-mask-position: center;
    mask-position: center;
}

.tpd-card .image.background {
    transform: rotateX(var(--rotateX, 0deg)) rotateY(var(--rotateY, 0deg)) translate3d(0, 0, 0rem);
}

.tpd-card .image.cutout {
    transform: rotateX(var(--rotateX, 0deg)) rotateY(var(--rotateY, 0deg)) translate3d(0, 0, 4rem) scale(0.92);
    z-index: 3;
}

.tpd-card .content {
    position: absolute;
    display: flex;
    flex-direction: column;
    justify-content: flex-end;
    inset: 0;
    padding: 3.5rem;
    transform: rotateX(var(--rotateX, 0deg)) rotateY(var(--rotateY, 0deg)) translate3d(0, 0, 6rem);
    z-index: 4;
}

.tpd-card::after, .tpd-card::before {
    content: "";
    position: absolute;
    inset: 1.5rem;
    border: #e2c044 0.5rem solid;
    transform: rotateX(var(--rotateX, 0deg)) rotateY(var(--rotateY, 0deg)) translate3d(0, 0, 2rem);
}

.tpd-card::before { z-index: 4; }
.tpd-card.border-left-behind::before { border-left: transparent; }
.tpd-card.border-right-behind::before { border-right: transparent; }
.tpd-card.border-bottom-behind::before { border-bottom: transparent; }

.tpd-card h2 {
    font-size: 1.25rem;
    font-weight: 700;
    margin-bottom: 0.5rem;
    text-shadow: 0 0 2rem rgba(0, 0, 0, 0.5);
}

.tpd-card p {
    font-weight: 300;
    text-shadow: 0 0 2rem rgba(0, 0, 0, 0.5);
    margin: 0;
}
</style>

<div class="tpd-3d-wrapper">
    <div class="tpd-centered">
        <div class="tpd-card border-left-behind" data-rotate-x="0" data-rotate-y="0">
            <div class="shadow" style="--url: url('https://i.ibb.co/PM4ghD4/full.png')"></div>
            <div class="image background" style="--url: url('https://i.ibb.co/JpJVJxq/Background.png')"></div>
            <div class="image cutout" style="--url: url('https://i.ibb.co/Dw3q3tZ/cutout.png')"></div>
            <div class="content">
                <h2>Hover me!</h2>
                <p>3D Parallax Effect with CSS & JS.</p>
            </div>
        </div>
        <div class="tpd-card border-right-behind border-bottom-behind" data-rotate-x="0" data-rotate-y="0">
            <div class="shadow" style="--url: url('https://i.ibb.co/DC0MbxS/m-full.png')"></div>
            <div class="image background" style="--url: url('https://i.ibb.co/ZdGBm4K/m-background.png')"></div>
            <div class="image cutout" style="--url: url('https://i.ibb.co/RC70XmC/m-cutout.png')"></div>
            <div class="content">
                <h2>Hover me!</h2>
                <p>Interactive depth and motion.</p>
            </div>
        </div>
    </div>
</div>
  

  <script>
// --- JavaScript Area ---
(function() {
    const angle = 20;
    const lerp = (start, end, amount) => (1 - amount) * start + amount * end;
    const remap = (value, oldMax, newMax) => {
        const newValue = ((value + oldMax) * (newMax * 2)) / (oldMax * 2) - newMax;
        return Math.min(Math.max(newValue, -newMax), newMax);
    };

    const cards = document.querySelectorAll(".tpd-card");
    cards.forEach((e) => {        
        e.addEventListener("mousemove", (event) => {
            const rect = e.getBoundingClientRect();
            const centerX = (rect.left + rect.right) / 2;
            const centerY = (rect.top + rect.bottom) / 2;
            const posX = event.clientX - centerX;
            const posY = event.clientY - centerY;
            e.dataset.targetX = remap(posX, rect.width / 2, angle);
            e.dataset.targetY = -remap(posY, rect.height / 2, angle);
        });
        
        e.addEventListener("mouseleave", () => {
            e.dataset.targetX = 0;
            e.dataset.targetY = 0;
        });
    });
    
    const update = () => {
        cards.forEach((e) => {
            const targetX = parseFloat(e.dataset.targetX) || 0;
            const targetY = parseFloat(e.dataset.targetY) || 0;
            const currentX = parseFloat(e.dataset.currentX) || 0;
            const currentY = parseFloat(e.dataset.currentY) || 0;

            const x = lerp(currentX, targetX, 0.1);
            const y = lerp(currentY, targetY, 0.1);

            e.dataset.currentX = x;
            e.dataset.currentY = y;

            e.style.setProperty("--rotateY", x + "deg");
            e.style.setProperty("--rotateX", y + "deg");
        });
        requestAnimationFrame(update);
    }
    requestAnimationFrame(update);
})();
</script>
  
まつゆう
アラフォーゲーマーがいろんなゲームを楽しみながらプレイしています。YouTube・Twitch・Mixerで配信中!! 東京パフォーマンスドールの狂信者。 好きすぎてドメインを取得してファンサイトを運営中。

0 comments:

コメントを投稿