做一个简单的圆脸心情鼠标跟踪效果动态图
完整的代码如下:
<!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>
具体效果小伙伴们可以自行尝试下。
有兴趣的小伙伴可以优化下眼睛移动时的变化,同时也可以优化下嘴角的变化过渡