Многошаговая форма (multi-step form) разбивает ввод данных на логические этапы, улучшая восприятие и снижая когнитивную нагрузку. В контексте ScrollMagic каждый шаг может быть связан с прокруткой страницы, создавая интерактивный сценарий, где переходы между шагами управляются скроллом.
Основные компоненты:
Каждый шаг формы оформляется как отдельный контейнер:
<form id="multi-step-form">
<section class="step" data-step="1">
<h2>Шаг 1</h2>
<input type="text" name="name" placeholder="Имя">
</section>
<section class="step" data-step="2">
<h2>Шаг 2</h2>
<input type="email" name="email" placeholder="Email">
</section>
<section class="step" data-step="3">
<h2>Шаг 3</h2>
<input type="password" name="password" placeholder="Пароль">
</section>
</form>
CSS подготавливает базовую визуализацию:
.step {
height: 100vh;
opacity: 0.3;
transition: opacity 0.5s ease;
}
.step.active {
opacity: 1;
}
const controller = new ScrollMagic.Controller();
Контроллер управляет всеми сценами, связанными с шагами формы.
Каждый шаг связывается с отдельной сценой:
document.querySelectorAll('.step').forEach((step, index) => {
new ScrollMagic.Scene({
triggerElement: step,
triggerHook: 0.5,
duration: '100%'
})
.on('enter', () => setActiveStep(index))
.addTo(controller);
});
Ключевые параметры:
function setActiveStep(index) {
document.querySelectorAll('.step').forEach((step, i) => {
step.classList.toggle('active', i === index);
});
}
При входе в сцену шаг становится активным.
ScrollMagic позволяет «закрепить» форму на экране, пока пользователь прокручивает шаги:
new ScrollMagic.Scene({
triggerElement: '#multi-step-form',
triggerHook: 0,
duration: '300%'
})
.setPin('#multi-step-form')
.addTo(controller);
Это создаёт эффект «прокрутки внутри формы», когда сами шаги сменяются, а форма остаётся на месте.
Для плавных переходов используется GSAP:
document.querySelectorAll('.step').forEach((step) => {
new ScrollMagic.Scene({
triggerElement: step,
triggerHook: 0.7,
reverse: true
})
.setTween(step, { y: 50, opacity: 1, duration: 0.5 })
.addTo(controller);
});
Анимация:
Переход к следующему шагу можно ограничить:
function validateStep(stepElement) {
const inputs = stepElement.querySelectorAll('input');
return [...inputs].every(input => input.value.trim() !== '');
}
Использование в сцене:
.on('enter', (event) => {
if (!validateStep(step)) {
controller.scrollTo(step);
}
});
ScrollMagic поддерживает управление скроллом:
controller.scrollTo((newPos) => {
window.scrollTo({
top: newPos,
beh * avior: 'smooth'
});
});
Переход к следующему шагу:
function goToStep(index) {
const step = document.querySelectorAll('.step')[index];
controller.scrollTo(step);
}
Прогресс формы отображается через прогресс-бар:
<div class="progress">
<div class="progress-bar"></div>
</div>
.progress {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 5px;
}
.progress-bar {
height: 100%;
width: 0;
background: #3498db;
}
Обновление:
controller.scrollPos(() => window.scrollY);
controller.update(true);
window.addEventListener('scroll', () => {
const maxScroll = document.body.scrollHeight - window.innerHeight;
const progress = (window.scrollY / maxScroll) * 100;
document.querySelector('.progress-bar').style.width = progress + '%';
});
Для предотвращения потери данных:
const formData = {};
document.querySelectorAll('input').forEach(input => {
input.addEventListener('input', (e) => {
formData[e.target.name] = e.target.value;
});
});
Восстановление:
window.addEventListener('load', () => {
Object.keys(formData).forEach(name => {
const input = document.querySelector(`[name="${name}"]`);
if (input) input.value = formData[name];
});
});
Некоторые шаги могут требовать загрузки данных:
async function loadStepData(step) {
const response = await fetch('/api/data');
const data = await response.json();
step.querySelector('.content').innerText = data.text;
}
Интеграция:
.on('enter', () => {
if (!step.dataset.loaded) {
loadStepData(step);
step.dataset.loaded = true;
}
});
Последний шаг может отправлять данные:
function submitForm() {
fetch('/submit', {
method: 'POST',
body: JSON.stringify(formData),
headers: {
'Content-Type': 'application/json'
}
});
}
Привязка:
if (index === lastStepIndex) {
submitForm();
}
triggerHook вместо сложных вычисленийreverse, если обратная анимация не
требуетсяconst isMobile = window.innerWidth < 768;
if (isMobile) {
controller.enabled(false);
}
const event = new CustomEvent('stepChange', {
detail: { step: index }
});
window.dispatchEvent(event);
Подписка:
window.addEventListener('stepChange', (e) => {
console.log('Текущий шаг:', e.detail.step);
});
ScrollMagic часто используется совместно с:
Пример с GSAP Timeline:
const timeline = gsap.timeline();
timeline
.from('.step h2', { opacity: 0, y: 20 })
.from('.step input', { opacity: 0, y: 20 }, '-=0.2');
new ScrollMagic.Scene({
triggerElement: '.step',
triggerHook: 0.5
})
.setTween(timeline)
.addTo(controller);
duration → неожиданные переходыРекомендуется разделять:
Пример:
class MultiStepForm {
constructor() {
this.controller = new ScrollMagic.Controller();
this.steps = document.querySelectorAll('.step');
this.initScenes();
}
initScenes() {
this.steps.forEach((step, index) => {
new ScrollMagic.Scene({
triggerElement: step,
triggerHook: 0.5
})
.on('enter', () => this.setActiveStep(index))
.addTo(this.controller);
});
}
setActiveStep(index) {
this.steps.forEach((step, i) => {
step.classList.toggle('active', i === index);
});
}
}
new MultiStepForm();
Такой подход упрощает поддержку и масштабирование многошаговой формы.