Плавное появление при скролле
Элементы анимированно появляются при входе в viewport —
IntersectionObserverдобавляет CSS-класс,transitionделает анимацию.
Задача
Секции лендинга, карточки, блоки текста должны появляться с плавной анимацией при прокрутке к ним — эффект «reveal on scroll» без тяжёлых библиотек.
Решение
<!-- Добавь класс .reveal к элементам, которые должны появляться -->
<section class="reveal">Секция 1</section>
<div class="reveal">Карточка</div>
<article class="reveal">Статья</article>
/* Начальное состояние: скрытый и сдвинутый вниз */
.reveal {
opacity: 0;
transform: translateY(40px);
transition: opacity 0.6s ease, transform 0.6s ease;
}
/* Видимое состояние */
.reveal.visible {
opacity: 1;
transform: translateY(0);
}
/* Задержки для каскадного появления (опционально) */
.reveal:nth-child(2) { transition-delay: 0.1s; }
.reveal:nth-child(3) { transition-delay: 0.2s; }
.reveal:nth-child(4) { transition-delay: 0.3s; }
/* Уважаем настройки пользователя */
@media (prefers-reduced-motion: reduce) {
.reveal { transition: none; opacity: 1; transform: none; }
}
const elements = document.querySelectorAll('.reveal');
const observer = new IntersectionObserver(
(entries) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
entry.target.classList.add('visible');
observer.unobserve(entry.target); // показать только один раз
}
});
},
{
threshold: 0.15, // 15% элемента должно быть видно
rootMargin: '0px 0px -50px 0px', // чуть позже — не сразу у края
}
);
elements.forEach((el) => observer.observe(el));
Варианты анимации через data-атрибут:
<div class="reveal" data-reveal="fade-left">Слева</div>
<div class="reveal" data-reveal="fade-right">Справа</div>
<div class="reveal" data-reveal="zoom">Zoom</div>
[data-reveal="fade-left"] { transform: translateX(-40px); }
[data-reveal="fade-right"] { transform: translateX(40px); }
[data-reveal="zoom"] { transform: scale(0.85); }
[data-reveal].visible { transform: none; opacity: 1; }
Ключевые моменты
IntersectionObserver+ CSS class — минимум JS, анимация полностью в CSS.observer.unobserve()— элемент появляется один раз и перестаёт отслеживаться.@media (prefers-reduced-motion: reduce)— обязательна; пользователи с вестибулярными нарушениями отключают анимации.rootMargin: '0px 0px -50px 0px'— нижний отступ 50px, элемент появится чуть позже прихода в viewport.
Варианты
- AOS (
animate on scroll) — готовая библиотека с десятками анимаций,data-aosатрибуты. - GSAP ScrollTrigger — для сложных timeline-анимаций, привязанных к позиции скролла.