Анимированный эффект отслеживания мыши
Вот код представляющий элегантную реализацию эффекта отслеживания курсора мыши с учетом современных требований доступности и производительности. Разберем каждую часть кода подробно.
HTML структура
HTML
<!-- Заголовок демонстрации -->
<h1>Mouse Tracking Animation</h1>
<!-- Кнопка для демонстрации взаимодействия с эффектом -->
<a href="#" class="btn">Hover Me</a>
<!-- Блок для отображения координат курсора в реальном времени -->
<p id="coordinates">
Coordinates<br>
<strong></strong> <!-- Здесь будут отображаться x и y координаты -->
</p>
<!-- Элемент-указатель, который будет следовать за курсором -->
<!-- aria-hidden="true" скрывает элемент от экранных читалок,
так как он носит чисто декоративный характер -->
<div class="pointer" aria-hidden="true"></div>CSS стилизация
Базовые стили и фон
CSS
/* Сброс всех отступов и установка корректной модели блоков */
* {
margin: 0;
padding: 0;
box-sizing: border-box; /* Включает padding и border в общую ширину */
}
body {
font-family: system-ui, sans-serif; /* Использует системный шрифт */
font-size: 1rem;
line-height: 1.7; /* Улучшает читаемость текста */
color: #070707;
/* Создание сложного градиентного фона с сеточным паттерном */
background:
/* Градиент от прозрачного к белому */
fixed linear-gradient(transparent, #fff 70%),
/* Вертикальные линии сетки каждые 40px */
fixed repeating-linear-gradient(
#efefef,
#efefef 1px,
transparent 1px,
transparent 40px
),
/* Горизонтальные линии сетки каждые 40px */
fixed repeating-linear-gradient(
to right,
#efefef,
#efefef 1px,
transparent 1px,
transparent 40px
)
#fff; /* Базовый белый фон */
padding: 0 2rem;
text-align: center;
height: 100svh; /* Новая единица измерения - 100% высоты экрана */
/* Flexbox для центрирования контента */
display: flex;
justify-content: center;
align-items: center;
flex-flow: column;
gap: 1.5rem;
}Стили заголовка
CSS
h1 {
/* Адаптивный размер шрифта с помощью clamp() */
font-size: clamp(2.5rem, 2vw + 2rem, 6rem);
line-height: 1.3;
font-weight: 900; /* Максимальная жирность */
text-transform: uppercase; /* Заглавные буквы */
}Стили кнопки
CSS
.btn {
display: inline-block;
padding: 1rem 4rem;
font-size: 1.25rem;
font-weight: 700;
color: currentColor; /* Наследует цвет от родителя */
text-align: center;
text-decoration: none;
border: 1px solid #ff8059; /* Оранжевая граница */
border-radius: 0.5rem;
outline: none;
/* Плавные переходы для цвета и фона */
transition: 0.5s ease-out;
transition-property: color, background-color;
}
/* Эффекты при наведении и фокусе */
.btn:hover,
.btn:focus-visible {
color: #fff; /* Белый текст */
background-color: #ff8059; /* Оранжевый фон */
}Главный элемент — указатель
CSS
.pointer {
position: fixed; /* Фиксированное позиционирование относительно окна */
top: 0;
left: 0;
z-index: 999; /* Высокий z-index для отображения поверх всего */
width: 2rem;
aspect-ratio: 1; /* Квадратная форма (ширина = высоте) */
background-color: rgb(0 0 0 / 25%); /* Полупрозрачный черный фон */
border: 1px solid transparent;
border-radius: 100%; /* Круглая форма */
pointer-events: none; /* Не блокирует клики мышью */
/* Ключевая часть: использование CSS-переменных для позиционирования */
transform: translate3d(var(--mouseX, 0), var(--mouseY, 0), 0)
translate(-50%, -50%);
/* Плавные переходы для всех изменений */
transition: 0.3s ease-out;
transition-property: transform, width, border, background-color;
}
/* Эффект при наведении на кнопку - указатель увеличивается */
body:has(.btn:hover) .pointer {
width: 5rem; /* Увеличенный размер */
background-color: transparent; /* Прозрачный фон */
border-color: rgb(0 0 0 / 50%); /* Видимая граница */
}Медиа-запросы для доступности
CSS
/* Скрытие анимации для пользователей с настройкой "уменьшить движение" */
@media (prefers-reduced-motion: reduce) {
.pointer,
#coordinates {
display: none; /* Полностью скрываем элементы */
}
}
/* Скрытие для сенсорных устройств (телефоны, планшеты) */
@media (pointer: coarse) {
.pointer,
#coordinates {
display: none;
}
}JavaScript логика
JavaScript
// Проверка настроек пользователя на уменьшение анимации
const isReducedMotion = window.matchMedia("(prefers-reduced-motion: reduce)")
.matches;
// Проверка на сенсорное устройство
const isTouch = window.matchMedia("(pointer: coarse)").matches;
// Определяем, должна ли запускаться анимация
// Анимация работает только на не-сенсорных устройствах
// и когда пользователь не запрашивал уменьшение движения
const shouldRun = !isReducedMotion && !isTouch;
if (shouldRun) {
// Переменные для хранения координат мыши
let mouseX = 0;
let mouseY = 0;
// Получение ссылок на DOM элементы
const pointer = document.querySelector(".pointer");
const coordinates = document.querySelector("#coordinates strong");
// Обработчик события движения мыши
window.addEventListener("mousemove", (e) => {
// Сохраняем координаты курсора относительно окна браузера
mouseX = e.clientX;
mouseY = e.clientY;
// Опциональное логирование для отладки
// console.log(mouseX, mouseY);
// Обновление отображения координат в DOM
if (coordinates) {
coordinates.innerText = `x: ${mouseX} y: ${mouseY}`;
}
});
// Функция анимации, использующая requestAnimationFrame
function animate() {
// Установка CSS-переменных для позиционирования указателя
// setProperty позволяет динамически изменять CSS custom properties
pointer.style.setProperty("--mouseX", `${mouseX}px`);
pointer.style.setProperty("--mouseY", `${mouseY}px`);
// Запрос следующего кадра анимации
// Это обеспечивает синхронизацию с частотой обновления экрана (обычно 60 FPS)
requestAnimationFrame(animate);
}
// Запуск цикла анимации
animate();
}Ключевые технологии и концепции
1. CSS Custom Properties (переменные)
Использование --mouseX и --mouseY позволяет JavaScript динамически обновлять позицию элемента без прямого манипулирования DOM.
2. transform: translate3d()
Использование translate3d() вместо изменения top/left обеспечивает аппаратное ускорение и лучшую производительность.
3. requestAnimationFrame()
Этот метод синхронизирует анимацию с частотой обновления экрана, обеспечивая плавность и оптимизируя производительность.
4. Доступность (Accessibility)
prefers-reduced-motion— уважает настройки пользователя по уменьшению анимацииpointer: coarse— определяет сенсорные устройстваaria-hidden="true"— скрывает декоративный элемент от скринридеров
5. Производительность
pointer-events: none— предотвращает блокировку событий мыши- Использование
shouldRunфлага для предотвращения ненужных вычислений - Оптимизированная анимационная петля с
requestAnimationFrame
Принципы работы
- Инициализация: Код проверяет поддержку устройства и предпочтения пользователя
- Отслеживание: Событие
mousemoveсохраняет координаты курсора - Анимация:
requestAnimationFrameобновляет CSS-переменные каждый кадр - Отображение: CSS использует переменные для плавного перемещения указателя
- Интерактивность: При наведении на кнопку указатель изменяет размер и стиль
Этот код демонстрирует современный подход к веб-анимации с учетом производительности, доступности и пользовательского опыта.
Позаимствовано отсюда: YouTube