做一个简单的圆脸心情鼠标跟踪效果动态图

0 阅读4分钟

image.png

完整的代码如下:


<!DOCTYPE html>
<html>
<head>
    <title>互动表情</title>
    <style>
        /* 基础页面样式 */
        body {
            margin: 0;
            height: 100vh; /* 全屏高度 */
            display: flex;
            justify-content: center; /* 水平居中 */
            align-items: center; /* 垂直居中 */
            background: #f5f5f5; /* 浅灰色背景 */
            overflow: hidden; /* 隐藏溢出内容 */
            cursor: default; /* 默认鼠标指针 */
        }
        
        /* 表情容器 */
        .face-container {
            position: relative;
            width: 400px;
            height: 500px;
        }
        
        /* 脸部基础样式 */
        .face {
            position: relative;
            width: 400px;
            height: 400px;
            background: #FFD700; /* 金色背景 */
            border-radius: 50%; /* 圆形 */
            box-shadow: 0 0 40px rgba(0,0,0,0.15); /* 柔和阴影 */
            overflow: hidden; /* 隐藏溢出内容 */
        }
        
        /* 眼睛基础样式 */
        .eye {
            position: absolute;
            width: 70px;
            height: 70px;
            background: white; /* 白色眼白 */
            border-radius: 50%; /* 圆形 */
            top: 80px; /* 垂直位置 */
            z-index: 10; /* 确保在脸部上方 */
            box-shadow: 0 5px 15px rgba(0,0,0,0.2); /* 立体阴影 */
            transition: transform 0.2s ease-out; /* 平滑变换 */
            perspective: 1000px; /* 3D透视效果 */
        }
        
        /* 左眼定位 */
        .eye.left {
            left: 60px;
        }
        
        /* 右眼定位 */
        .eye.right {
            right: 60px;
        }
        
        /* 瞳孔样式 */
        .pupil {
            position: absolute;
            width: 30px;
            height: 30px;
            background: #222; /* 深灰色瞳孔 */
            border-radius: 50%; /* 圆形 */
            top: 20px;
            left: 20px;
            transition: all 0.1s ease; /* 平滑移动 */
            transform-style: preserve-3d; /* 保持3D变换 */
        }
        
        /* 瞳孔3D效果 */
        .pupil::before {
            content: '';
            position: absolute;
            width: 100%;
            height: 100%;
            background: #111; /* 更深的瞳孔颜色 */
            border-radius: 50%;
            transform: translateZ(-15px); /* 3D深度效果 */
        }
        
        /* 嘴巴容器 */
        .mouth-container {
            position: absolute;
            width: 200px;
            height: 100px;
            bottom: 80px; /* 底部位置 */
            left: 50%;
            transform: translateX(-50%); /* 水平居中 */
            overflow: hidden; /* 隐藏溢出内容 */
        }
        
        /* 嘴巴样式 */
        .mouth {
            position: absolute;
            width: 100%;
            height: 100%;
            background: #FF6B6B; /* 红色嘴巴 */
            border-radius: 0 0 100px 100px; /* 半圆形底部 */
            transition: all 0.8s cubic-bezier(0.25, 0.1, 0.25, 1); /* 弹性动画 */
        }
        
        /* 按钮容器 */
        .btn-container {
            position: absolute;
            width: 100%;
            bottom: 10px; /* 底部位置 */
            display: flex;
            justify-content: space-between; /* 按钮左右分布 */
            padding: 0 30px;
            box-sizing: border-box;
        }
        
        /* 基础按钮样式 */
        .btn {
            padding: 12px 24px;
            border: none;
            border-radius: 30px; /* 圆角按钮 */
            background: linear-gradient(145deg, #4CAF50, #81C784); /* 绿色渐变 */
            color: white;
            font-size: 18px;
            font-weight: bold;
            cursor: pointer;
            box-shadow: 0 6px 12px rgba(0,0,0,0.2); /* 按钮阴影 */
            transition: all 0.3s; /* 悬停动画 */
        }
        
        /* 按钮悬停效果 */
        .btn:hover {
            transform: scale(1.1); /* 放大效果 */
            box-shadow: 0 8px 16px rgba(0,0,0,0.3); /* 更强的阴影 */
        }
        
        /* 否定按钮样式 */
        .btn-no {
            background: linear-gradient(145deg, #F44336, #E57373); /* 红色渐变 */
        }
        
        /* 彩花效果 */
        .confetti {
            position: absolute;
            width: 12px;
            height: 12px;
            animation: fall 3s ease-in forwards; /* 下落动画 */
            z-index: 5; /* 在脸部下方 */
            transform-origin: center bottom; /* 旋转中心 */
            opacity: 0.8; /* 半透明 */
            background-size: contain;
            background-repeat: no-repeat;
        }
        
        /* 彩花下落动画 */
        @keyframes fall {
            0% {
                transform: translateY(-100px) rotate(0deg) scale(0.8);
                opacity: 1;
            }
            100% {
                transform: translateY(600px) rotate(720deg) scale(1.2);
                opacity: 0;
            }
        }
        
        /* 脸颊样式 */
        .cheek {
            position: absolute;
            width: 50px;
            height: 30px;
            background: rgba(255,192,203,0.4); /* 粉色半透明 */
            border-radius: 50%; /* 圆形 */
            bottom: 90px; /* 嘴巴上方 */
            transition: all 0.5s ease; /* 平滑变化 */
        }
        
        /* 左脸颊定位 */
        .cheek.left {
            left: 50px;
        }
        
        /* 右脸颊定位 */
        .cheek.right {
            right: 50px;
        }
    </style>
</head>
<body>
    <!-- 主容器 -->
    <div class="face-container">
        <!-- 脸部 -->
        <div class="face">
            <!-- 左眼 -->
            <div class="eye left">
                <div class="pupil"></div>
            </div>
            <!-- 右眼 -->
            <div class="eye right">
                <div class="pupil"></div>
            </div>
            <!-- 左脸颊 -->
            <div class="cheek left"></div>
            <!-- 右脸颊 -->
            <div class="cheek right"></div>
            <!-- 嘴巴容器 -->
            <div class="mouth-container">
                <div class="mouth"></div>
            </div>
        </div>
        <!-- 按钮容器 -->
        <div class="btn-container">
            <button class="btn btn-no">不行</button>
            <button class="btn btn-yes">可以</button>
        </div>
    </div>

    <script>
        // 页面加载完成后初始化嘴巴形状
        document.addEventListener('DOMContentLoaded', () => {
            const mouth = document.querySelector('.mouth');
            mouth.style.borderRadius = "0 0 100px 100px";
        });

        // 鼠标移动时更新表情
        document.addEventListener('mousemove', (e) => {
            const face = document.querySelector('.face');
            const pupils = document.querySelectorAll('.pupil');
            const mouth = document.querySelector('.mouth');
            const cheeks = document.querySelectorAll('.cheek');
            
            // 获取脸部中心坐标
            const faceRect = face.getBoundingClientRect();
            const faceCenterX = faceRect.left + faceRect.width / 2;
            const faceCenterY = faceRect.top + faceRect.height / 2;
            
            // 鼠标坐标
            const mouseX = e.clientX;
            const mouseY = e.clientY;
            
            // 计算相对位置
            const relX = (mouseX - faceCenterX) / (faceRect.width / 2);
            const relY = (mouseY - faceCenterY) / (faceRect.height / 2);
            
            // 更新瞳孔位置
            pupils.forEach(pupil => {
                const eye = pupil.parentElement;
                const maxMove = 20; // 最大移动距离
                const moveX = relX * maxMove;
                const moveY = relY * maxMove * 0.5; // 垂直移动幅度较小
                
                // 应用3D变换
                pupil.style.transform = `translate(${moveX}px, ${moveY}px) translateZ(10px)`;
                
                // 根据鼠标位置缩放眼睛
                const scale = 1 + Math.abs(relX) * 0.3;
                eye.style.transform = `scale(${scale})`;
                eye.style.boxShadow = `0 ${5 + Math.abs(relX) * 5}px ${15 + Math.abs(relX) * 10}px rgba(0,0,0,0.3)`;
            });
            
            // 根据鼠标位置更新表情
            if (relX > 0) {
                // 右侧 - 开心表情
                const happiness = Math.min(1, relX);
                const curve = 100 + happiness * 80;
                mouth.style.borderRadius = `0 0 ${curve}px ${curve}px`;
                mouth.style.transform = `translateY(${happiness * -15}px) scale(${1 + happiness * 0.1})`;
                cheeks.forEach(cheek => {
                    cheek.style.transform = `scale(${1 + happiness * 0.2})`;
                    cheek.style.background = `rgba(255,192,203,${0.4 + happiness * 0.3})`;
                });
            } else {
                // 左侧 - 悲伤表情
                const sadness = Math.min(1, -relX);
                const curve = 100 + sadness * 80;
                mouth.style.borderRadius = `${curve}px ${curve}px 0 0`;
                mouth.style.transform = `translateY(${sadness * 40}px) scale(${1 - sadness * 0.05})`;
                cheeks.forEach(cheek => {
                    cheek.style.transform = `scale(${1 - sadness * 0.1})`;
                    cheek.style.background = `rgba(255,192,203,${0.4 - sadness * 0.2})`;
                });
            }
        });

        // "可以"按钮点击事件 - 触发彩花效果
        document.querySelector('.btn-yes').addEventListener('click', function() {
            this.blur(); // 移除焦点
            const faceContainer = document.querySelector('.face-container');
            const confettiTypes = [
                '💰', '🎉', '🎁', '✨', '❤️', '💎', '🏆', '⭐', '🍀', '🎈'
            ];
            
            // 创建单个彩花
            function createConfetti() {
                const confetti = document.createElement('div');
                confetti.className = 'confetti';
                // 随机选择彩花类型
                confetti.textContent = confettiTypes[Math.floor(Math.random() * confettiTypes.length)];
                confetti.style.fontSize = `${12 + Math.random() * 16}px`; // 随机大小
                confetti.style.color = `hsl(${Math.random() * 360}, 100%, 50%)`; // 随机颜色
                
                // 随机位置
                confetti.style.left = `${Math.random() * faceContainer.offsetWidth}px`;
                confetti.style.top = `-30px`;
                confetti.style.transform = `rotate(${Math.random() * 360}deg)`;
                confetti.style.opacity = `${0.7 + Math.random() * 0.3}`;
                confetti.style.animationDuration = `${2 + Math.random() * 2}s`;
                
                faceContainer.appendChild(confetti);
                
                // 3秒后移除彩花
                setTimeout(() => {
                    confetti.remove();
                }, 3000);
            }
            
            // 创建100个彩花,分批出现
            for (let i = 0; i < 100; i++) {
                setTimeout(createConfetti, i * 50);
            }
        });
    </script>
</body>
</html>

具体效果小伙伴们可以自行尝试下。

有兴趣的小伙伴可以优化下眼睛移动时的变化,同时也可以优化下嘴角的变化过渡

祝大家周末玩的开心。