Step 4 of 10

Interactive Elements

📖 Lesson

CSS Animations

CSS can animate elements - smoothly changing their properties over time.

@keyframes fade-in {
  from { opacity: 0; }
  to { opacity: 1; }
}

This defines a "fade-in" animation that gradually shows an element.

CSS animations make a page come alive without a single line of JavaScript!

Transition vs. Animation

Transition = one-time change (e.g., on hover):

button { transition: all 0.3s ease; }
button:hover { transform: scale(1.1); }

Animation = repeating or more complex motion:

.element {
  animation: float 3s ease-in-out infinite;
}
Transition for simple effects, animation for complex motions.

Transform - change shape

transform lets you change elements without affecting surrounding ones:

  • scale(1.2) - enlarge by 20%
  • rotate(45deg) - rotate by 45 degrees
  • translateY(-10px) - move up
  • perspective + rotateY - 3D effect

In today's example you'll see a card that flips on hover!

💻 Example to try
index.php
🚀 Try on Vibmy
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Interactive Cards</title>
    <style>
        * { margin: 0; padding: 0; box-sizing: border-box; }

        body {
            min-height: 100vh;
            font-family: "Segoe UI", system-ui, sans-serif;
            background: #0a0a1a;
            overflow-x: hidden;
        }

        /* Animated gradient background */
        .bg-gradient {
            position: fixed;
            top: 0; left: 0; right: 0; bottom: 0;
            background: linear-gradient(-45deg, #0f0c29, #1a1a3e, #0f2027, #1a0a2e);
            background-size: 400% 400%;
            animation: gradientShift 15s ease infinite;
            z-index: 0;
        }

        @keyframes gradientShift {
            0% { background-position: 0% 50%; }
            50% { background-position: 100% 50%; }
            100% { background-position: 0% 50%; }
        }

        /* Floating particles */
        .particles {
            position: fixed;
            top: 0; left: 0; right: 0; bottom: 0;
            z-index: 1;
            pointer-events: none;
        }

        .particle {
            position: absolute;
            border-radius: 50%;
            animation: particleFloat linear infinite;
            opacity: 0;
        }

        @keyframes particleFloat {
            0% { transform: translateY(100vh) scale(0); opacity: 0; }
            10% { opacity: 1; }
            90% { opacity: 1; }
            100% { transform: translateY(-10vh) scale(1); opacity: 0; }
        }

        .content {
            position: relative;
            z-index: 2;
            padding: 3rem 2rem;
        }

        h1 {
            text-align: center;
            font-size: 2.5rem;
            color: #fff;
            margin-bottom: 0.5rem;
        }

        .subtitle {
            text-align: center;
            color: #8892a4;
            margin-bottom: 3rem;
            font-size: 1.1rem;
        }

        /* Flipping cards */
        .cards {
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
            gap: 2rem;
            max-width: 1000px;
            margin: 0 auto;
        }

        .flip-card {
            height: 320px;
            perspective: 1000px;
            cursor: pointer;
        }

        .flip-card-inner {
            width: 100%;
            height: 100%;
            transition: transform 0.8s cubic-bezier(0.175, 0.885, 0.32, 1.275);
            transform-style: preserve-3d;
            position: relative;
        }

        .flip-card:hover .flip-card-inner {
            transform: rotateY(180deg);
        }

        .flip-card-front, .flip-card-back {
            position: absolute;
            width: 100%;
            height: 100%;
            backface-visibility: hidden;
            border-radius: 20px;
            display: flex;
            flex-direction: column;
            align-items: center;
            justify-content: center;
            padding: 2rem;
            text-align: center;
        }

        .flip-card-front {
            background: rgba(255,255,255,0.05);
            border: 1px solid rgba(255,255,255,0.1);
            backdrop-filter: blur(10px);
        }

        .flip-card-back {
            background: linear-gradient(135deg, rgba(0,212,170,0.2), rgba(123,104,238,0.2));
            border: 1px solid rgba(0,212,170,0.3);
            transform: rotateY(180deg);
            backdrop-filter: blur(10px);
        }

        .flip-icon { font-size: 4rem; margin-bottom: 1rem; }
        .flip-card-front h3 { color: #f0f0f0; font-size: 1.4rem; margin-bottom: 0.5rem; }
        .flip-card-front p { color: #6b7280; font-size: 0.9rem; }
        .flip-card-back h3 { color: #00d4aa; font-size: 1.3rem; margin-bottom: 1rem; }
        .flip-card-back p { color: #d0d0d0; font-size: 0.95rem; line-height: 1.7; }

        .hint {
            text-align: center;
            color: #555;
            margin-top: 2rem;
            font-size: 0.9rem;
            animation: pulse 2s ease infinite;
        }

        @keyframes pulse {
            0%, 100% { opacity: 0.5; }
            50% { opacity: 1; }
        }

        /* Floating button */
        .float-btn {
            display: block;
            margin: 3rem auto 0;
            padding: 1rem 2.5rem;
            background: linear-gradient(135deg, #00d4aa, #7b68ee);
            color: #fff;
            border: none;
            border-radius: 50px;
            font-size: 1.1rem;
            cursor: pointer;
            animation: floatBtn 3s ease-in-out infinite;
            transition: transform 0.3s, box-shadow 0.3s;
            font-weight: 600;
        }

        .float-btn:hover {
            transform: scale(1.1);
            box-shadow: 0 10px 40px rgba(0,212,170,0.4);
        }

        @keyframes floatBtn {
            0%, 100% { transform: translateY(0); }
            50% { transform: translateY(-8px); }
        }

        @media (max-width: 600px) {
            h1 { font-size: 1.8rem; }
            .cards { grid-template-columns: 1fr; }
        }
    </style>
</head>
<body>
    <div class="bg-gradient"></div>

    <div class="particles" id="particles"></div>

    <div class="content">
        <h1>&#x2728; Interactive Cards</h1>
        <p class="subtitle">Hover over a card - it flips!</p>

        <div class="cards">
            <div class="flip-card">
                <div class="flip-card-inner">
                    <div class="flip-card-front">
                        <span class="flip-icon">&#x1F3A8;</span>
                        <h3>CSS Animations</h3>
                        <p>Hover for more</p>
                    </div>
                    <div class="flip-card-back">
                        <h3>CSS Magic</h3>
                        <p>This card flips using CSS transform and perspective. No JavaScript!</p>
                    </div>
                </div>
            </div>

            <div class="flip-card">
                <div class="flip-card-inner">
                    <div class="flip-card-front">
                        <span class="flip-icon">&#x1F680;</span>
                        <h3>Particles</h3>
                        <p>Hover for more</p>
                    </div>
                    <div class="flip-card-back">
                        <h3>Floating World</h3>
                        <p>Background particles are created with JavaScript and animated with CSS. A combination of both!</p>
                    </div>
                </div>
            </div>

            <div class="flip-card">
                <div class="flip-card-inner">
                    <div class="flip-card-front">
                        <span class="flip-icon">&#x1F308;</span>
                        <h3>Gradients</h3>
                        <p>Hover for more</p>
                    </div>
                    <div class="flip-card-back">
                        <h3>Living Colors</h3>
                        <p>The page background is an animated gradient - colors smoothly shift over time. A living background!</p>
                    </div>
                </div>
            </div>
        </div>

        <p class="hint">&#x1F446; Hover over the cards</p>

        <button class="float-btn" onclick="document.body.style.background='#'+Math.floor(Math.random()*16777215).toString(16)">
            &#x1F3B2; Random Color
        </button>
    </div>

    <script>
        // Generate floating particles
        const container = document.getElementById("particles");
        const colors = ["#00d4aa", "#7b68ee", "#ff6b9d", "#f59e0b", "#3b82f6"];

        for (let i = 0; i < 30; i++) {
            const particle = document.createElement("div");
            particle.classList.add("particle");
            const size = Math.random() * 6 + 2;
            particle.style.width = size + "px";
            particle.style.height = size + "px";
            particle.style.left = Math.random() * 100 + "%";
            particle.style.background = colors[Math.floor(Math.random() * colors.length)];
            particle.style.animationDuration = (Math.random() * 10 + 8) + "s";
            particle.style.animationDelay = (Math.random() * 10) + "s";
            container.appendChild(particle);
        }
    </script>
</body>
</html>
← Back 4 / 10 Next step →