← Назад к вопросам
Как наклонять карточку при наведении мышкой?
2.2 Middle🔥 161 комментариев
#JavaScript Core
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI3 апр. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Как наклонять карточку при наведении мышкой
Это популярный UI эффект, который создаёт ощущение глубины и интерактивности. Рассмотрим несколько подходов от простых к сложным.
1. Простой 3D tilt с CSS transform
Самый простой способ - использовать CSS transform при наведении:
<style>
.card {
width: 300px;
height: 200px;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
border-radius: 12px;
padding: 20px;
color: white;
cursor: pointer;
transition: transform 0.3s ease-out;
/* Включаем 3D перспективу для плавного наклона */
perspective: 1000px;
}
.card:hover {
/* Наклоняем карточку в 3D пространстве */
transform: rotateX(10deg) rotateY(-15deg) scale(1.05);
}
</style>
<div class="card">
<h3>Карточка</h3>
<p>Наведи мышку для эффекта</p>
</div>
2. Наклон в сторону мышки (более сложный эффект)
Для реалистичного эффекта, когда карточка наклоняется в сторону движения мышки, нужен JavaScript:
<style>
.card-container {
perspective: 1000px;
}
.card {
width: 300px;
height: 200px;
background: white;
border-radius: 12px;
padding: 20px;
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.1);
transition: transform 0.1s;
transform-style: preserve-3d;
}
</style>
<div class="card-container">
<div class="card"></div>
</div>
<script>
const card = document.querySelector('.card');
const container = document.querySelector('.card-container');
container.addEventListener('mousemove', (e) => {
const rect = container.getBoundingClientRect();
// Координаты мышки относительно карточки
const x = e.clientX - rect.left;
const y = e.clientY - rect.top;
// Центр карточки
const centerX = rect.width / 2;
const centerY = rect.height / 2;
// Угол наклона зависит от положения мышки
const rotateX = (y - centerY) / 10;
const rotateY = (centerX - x) / 10;
card.style.transform = `rotateX(${rotateX}deg) rotateY(${rotateY}deg) scale(1.05)`;
});
// Возвращаем в исходное состояние при уходе мышки
container.addEventListener('mouseleave', () => {
card.style.transform = 'rotateX(0deg) rotateY(0deg) scale(1)';
});
</script>
3. Профессиональный 3D tilt эффект
Для более изящного эффекта с освещением:
<style>
.card-wrapper {
perspective: 1000px;
width: 300px;
height: 200px;
}
.card {
position: relative;
width: 100%;
height: 100%;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
border-radius: 12px;
padding: 20px;
color: white;
transition: transform 0.2s;
transform-style: preserve-3d;
overflow: hidden;
}
/* Подсветка при наклоне */
.card::before {
content: '';
position: absolute;
top: -50%;
left: -50%;
width: 200%;
height: 200%;
background: radial-gradient(circle, rgba(255, 255, 255, 0.3) 0%, transparent 70%);
pointer-events: none;
opacity: 0;
transition: opacity 0.2s;
}
.card:hover::before {
opacity: 1;
}
.card-content {
position: relative;
z-index: 2;
}
</style>
<div class="card-wrapper">
<div class="card">
<div class="card-content">
<h3>Премиум карточка</h3>
<p>С эффектом тилта и подсветкой</p>
</div>
</div>
</div>
<script>
const card = document.querySelector('.card');
const wrapper = document.querySelector('.card-wrapper');
const maxTilt = 15; // Максимальный угол наклона
wrapper.addEventListener('mousemove', (e) => {
const rect = wrapper.getBoundingClientRect();
const x = e.clientX - rect.left;
const y = e.clientY - rect.top;
const centerX = rect.width / 2;
const centerY = rect.height / 2;
// Нормализуем координаты от -1 до 1
const normalizedX = (x - centerX) / centerX;
const normalizedY = (y - centerY) / centerY;
const rotateX = -normalizedY * maxTilt;
const rotateY = normalizedX * maxTilt;
card.style.transform = `rotateX(${rotateX}deg) rotateY(${rotateY}deg)`;
});
wrapper.addEventListener('mouseleave', () => {
card.style.transform = 'rotateX(0deg) rotateY(0deg)';
});
</script>
4. React компонент с 3D tilt
import { useState } from 'react';
function TiltCard() {
const [rotate, setRotate] = useState({ x: 0, y: 0 });
const [scale, setScale] = useState(1);
const maxTilt = 20;
const handleMouseMove = (e) => {
const rect = e.currentTarget.getBoundingClientRect();
const x = e.clientX - rect.left;
const y = e.clientY - rect.top;
const centerX = rect.width / 2;
const centerY = rect.height / 2;
const normalizedX = (x - centerX) / centerX;
const normalizedY = (y - centerY) / centerY;
setRotate({
x: -normalizedY * maxTilt,
y: normalizedX * maxTilt
});
setScale(1.05);
};
const handleMouseLeave = () => {
setRotate({ x: 0, y: 0 });
setScale(1);
};
return (
<div
className="w-72 h-48 bg-gradient-to-br from-blue-500 to-purple-600 rounded-xl p-6 text-white cursor-pointer"
style={{
perspective: '1000px',
transform: `rotateX(${rotate.x}deg) rotateY(${rotate.y}deg) scale(${scale})`,
transformStyle: 'preserve-3d',
transition: 'transform 0.1s'
}}
onMouseMove={handleMouseMove}
onMouseLeave={handleMouseLeave}
>
<h3 className="text-xl font-bold mb-2">Карточка</h3>
<p>Наклоняется к мышке</p>
</div>
);
}
export default TiltCard;
5. Использование библиотеки Tilt.js
Для простоты можно использовать готовую библиотеку:
<!-- Подключаем библиотеку -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/vanilla-tilt/1.8.0/vanilla-tilt.min.js"></script>
<style>
.tilt-card {
width: 300px;
height: 200px;
background: white;
border-radius: 12px;
padding: 20px;
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.1);
}
</style>
<div class="tilt-card" data-tilt>
<h3>Карточка с Vanilla Tilt</h3>
<p>Автоматически наклоняется</p>
</div>
<script>
VanillaTilt.init(document.querySelector('.tilt-card'), {
max: 25, // Максимальный угол наклона
speed: 300, // Скорость анимации
scale: 1.1, // Масштаб при наклоне
transition: true // Плавный переход
});
</script>
6. Оптимизированная версия с requestAnimationFrame
Для лучшей производительности:
class TiltCard {
constructor(element) {
this.card = element;
this.maxTilt = 20;
this.currentRotate = { x: 0, y: 0 };
this.targetRotate = { x: 0, y: 0 };
this.isHovering = false;
this.card.addEventListener('mouseenter', () => this.isHovering = true);
this.card.addEventListener('mouseleave', () => this.isHovering = false);
this.card.addEventListener('mousemove', (e) => this.handleMouseMove(e));
this.animate();
}
handleMouseMove(e) {
const rect = this.card.getBoundingClientRect();
const x = e.clientX - rect.left;
const y = e.clientY - rect.top;
const centerX = rect.width / 2;
const centerY = rect.height / 2;
const normalizedX = (x - centerX) / centerX;
const normalizedY = (y - centerY) / centerY;
this.targetRotate.x = -normalizedY * this.maxTilt;
this.targetRotate.y = normalizedX * this.maxTilt;
}
animate() {
// Плавная интерполяция (easing)
const easing = 0.1;
this.currentRotate.x += (this.targetRotate.x - this.currentRotate.x) * easing;
this.currentRotate.y += (this.targetRotate.y - this.currentRotate.y) * easing;
// Если не наводим, возвращаемся к 0
if (!this.isHovering) {
this.currentRotate.x *= 0.95;
this.currentRotate.y *= 0.95;
}
this.card.style.transform =
`rotateX(${this.currentRotate.x}deg) rotateY(${this.currentRotate.y}deg) scale(${this.isHovering ? 1.05 : 1})`;
requestAnimationFrame(() => this.animate());
}
}
// Использование
const card = document.querySelector('.card');
new TiltCard(card);
Итоговые рекомендации
- Простой случай: используй CSS transform + hover
- Профессиональный эффект: JavaScript с вычислением угла по положению мышки
- Оптимизация: используй requestAnimationFrame для плавной анимации
- Готовое решение: Vanilla Tilt библиотека
- Производительность: избегай частых reflows, используй transform вместо позиционирования
- Accessibility: помни, что некоторые пользователи предпочитают меньше движения (prefers-reduced-motion)