Skip to content
PПромтбук
RUEN
02Motion

Скролл-хореография: кинематографичный ритм страницы

Раскрытие секций при скролле, осознанный ритм, parallax с умом. Что и когда анимировать, чтобы ощущалось как кино, а не как 2014.

Скролл премиум-сайта ощущается как кино: каждый блок появляется в нужный момент, паузы продуманные, parallax работает на сюжет. Скролл среднего сайта ощущается как карусель: всё анимируется одновременно, всё на одной скорости, всё трясёт.

Этот промт — план хореографии скролла для {{page_type}}.

1. Кинематографичный скролл vs «всё анимируется»

КинематографичныйАнимация ради анимации
Один-два движения за viewportКаждый элемент въезжает
Easing соответствует семантикеbouncing для серьёзного продукта
Parallax работает на глубину сюжетаparallax везде, теряется фокус
Sticky-элементы держатся осмысленноsticky без causal-связи
Длительность 200-400ms800ms+, лагает восприятие

2. Tokens движения

Опираемся на 3 easing и 3 длительности:

--motion-ease-out:    cubic-bezier(0.16, 1, 0.3, 1);     /* enter, главный */
--motion-ease-in:     cubic-bezier(0.7, 0, 0.84, 0);      /* exit, реже */
--motion-ease-spring: cubic-bezier(0.34, 1.56, 0.64, 1); /* единичные акценты */

--motion-dur-fast: 150ms;  /* hover, micro */
--motion-dur-base: 250ms;  /* section reveal */
--motion-dur-slow: 400ms;  /* hero, long-distance */

Никаких произвольных значений за пределами этой шкалы.

3. Хореография: что и когда

Hero (первый viewport)

  • Без enter-анимации текста — он уже там, юзер открыл страницу
  • Если очень хочется: opacity 0 → 1 на 200ms, без translate
  • LCP-критично: не блокируй ассеты из-за анимации
  • Parallax: только тонкий fade фонового изображения через background-attachment: fixed или Framer Motion useScroll с малой амплитудой (≤ 60px)

Sections (по мере скролла)

  • Reveal pattern: opacity 0 → 1 + translateY 12px → 0, ease-out, 250-400ms
  • Триггер: когда top секции в 65% viewport (а не 100% — поздно)
  • Стаггер только для списков карточек: 50-80ms между элементами, не больше 6 элементов (после стаггер не читается)
  • Reveal один раз — не повторять при scroll вверх-вниз

Sticky elements

  • Sticky header — без анимации появления, всегда там
  • Sticky ToC — fade in после 80vh scrolled, fade out на последней секции
  • Sticky CTA bar (mobile) — appears после прохождения hero, исчезает на footer
  • Один sticky на viewport в данный момент; не комбинируй ToC + CTA bar + chat bubble + cookie banner

Section transitions

  • Не анимируй переход между секциями — это работает только в storytelling сайтах (Apple, Pitch)
  • Если делаешь — используй position: sticky + useScroll + opacity overlap, не snap-scroll (плохая UX)

Parallax

  • Background-image при скролле: depth × 0.3-0.5 от обычной скорости
  • НЕ применять parallax к тексту (читаемость)
  • НЕ применять parallax к интерактивным элементам (запутает)
  • Тестировать на мобильном: parallax часто разваливается

4. Реализация (Framer Motion + CSS)

Базовый reveal (большинство секций):

import { motion } from "framer-motion";

<motion.section
  initial={{ opacity: 0, y: 12 }}
  whileInView={{ opacity: 1, y: 0 }}
  viewport={{ once: true, margin: "0px 0px -35% 0px" }}
  transition={{ duration: 0.25, ease: [0.16, 1, 0.3, 1] }}
>
  ...
</motion.section>

Стаггер для grid:

<motion.div
  initial="hidden"
  whileInView="visible"
  viewport={{ once: true, margin: "0px 0px -25% 0px" }}
  variants={{ visible: { transition: { staggerChildren: 0.06 } } }}
>
  {items.map((item) => (
    <motion.div
      key={item.id}
      variants={{
        hidden: { opacity: 0, y: 12 },
        visible: { opacity: 1, y: 0, transition: { duration: 0.25, ease: [0.16, 1, 0.3, 1] } },
      }}
    >
      {item.content}
    </motion.div>
  ))}
</motion.div>

Hero parallax (тонкий):

const { scrollY } = useScroll();
const y = useTransform(scrollY, [0, 600], [0, 60]);
<motion.div style={{ y, backgroundImage: "url(/hero.jpg)", backgroundSize: "cover" }} className="absolute inset-0 -z-10" />

Critical:

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    transition-duration: 0.01ms !important;
  }
}

5. Анти-паттерны

  • ❌ Reveal-анимация на hero (LCP, перцептивная задержка)
  • translateY 60px на reveal (выглядит как «дёргается»)
  • ❌ Spring easing на серьёзном продукте (B2B SaaS — нет)
  • ❌ Parallax > 100px (теряется связь с контентом)
  • ❌ Стаггер на 12+ элементах (последние появляются через 1 секунду — раздражает)
  • ❌ Анимация каждого элемента отдельно — должна быть хореография блока, а не балет
  • ❌ Игнорирование prefers-reduced-motion
  • ❌ Снэп-скролл (scroll-snap-type: y mandatory) без сильной причины

Формат вывода

  1. Карта скролла: блочная схема страницы с метками «что анимируется при достижении этой точки»
  2. Tokens block: easing + duration values
  3. Реальный JSX/CSS для 3 ключевых паттернов: reveal, stagger grid, hero parallax
  4. prefers-reduced-motion fallback
  5. Перформанс-чеклист: что НЕ блокирует FCP/LCP, что использует transform/opacity (не layout-trigger)
К подразделу «Motion»
Похожие промты