Прогрессивное улучшение в контексте веб-анимаций означает построение интерфейса таким образом, чтобы базовая функциональность и визуальная структура оставались корректными без JavaScript, а расширенные анимационные возможности включались только при наличии поддержки.
В экосистеме Velocity.js это подход приобретает практическую значимость, поскольку библиотека часто используется для замены или расширения CSS-анимаций, обеспечивая более гибкое управление временем, очередями и производительностью.
Первый слой интерфейса должен существовать независимо от Velocity.js. Это означает, что элементы страницы обязаны иметь:
Пример базового подхода:
.card {
opacity: 1;
transform: translateY(0);
transition: none;
}
.modal {
display: block;
}
Такой стиль гарантирует, что даже при полном отсутствии JavaScript интерфейс остаётся функциональным. Velocity.js в таком случае становится улучшением, а не обязательным компонентом.
Velocity.js работает как надстройка над DOM-элементами, изменяя
свойства через высокопроизводительный механизм анимации, основанный на
requestAnimationFrame.
При прогрессивном улучшении важно, чтобы вызовы Velocity выполнялись только после проверки наличия среды выполнения:
if (window.Velocity) {
Velocity(document.querySelector('.card'), {
opacity: 1,
translateY: 0
}, {
duration: 400,
easing: "ease-out"
});
}
В таком подходе логика анимации не влияет на базовое отображение, а лишь модифицирует уже готовое состояние.
Ключевой принцип прогрессивного улучшения — разделение состояний:
.toast {
opacity: 1;
transform: translateY(0);
}
.toast.is-hidden {
opacity: 0;
transform: translateY(20px);
}
Velocity(document.querySelector('.toast'), "fadeIn", {
duration: 300
});
CSS обеспечивает корректное отображение при отсутствии JS, а Velocity.js лишь уточняет динамику перехода.
При построении интерфейсов с Velocity.js важно учитывать сценарии:
Каждая анимация должна иметь эквивалентное CSS-поведение:
.panel {
opacity: 1;
transform: translateX(0);
}
.panel.is-collapsed {
display: none;
}
if (window.Velocity) {
Velocity(panel, { translateX: "-100%" }, { duration: 250 });
} else {
panel.classList.add("is-collapsed");
}
Такой подход исключает зависимость UX от конкретной библиотеки.
Современный прогрессивный подход учитывает системные настройки пользователя:
@media (prefers-reduced-motion: reduce) {
.animated {
animation: none !important;
transition: none !important;
}
}
Velocity.js можно интегрировать с этой логикой через условное отключение анимаций:
const reduceMotion = window.matchMedia("(prefers-reduced-motion: reduce)").matches;
if (!reduceMotion && window.Velocity) {
Velocity(element, "fadeIn", { duration: 300 });
}
В прогрессивном улучшении Velocity.js не должен определять состояние интерфейса. Его роль ограничивается:
Состояния всегда остаются в CSS:
.sidebar {
width: 280px;
}
.sidebar.is-collapsed {
width: 0;
}
Velocity лишь управляет переходом:
Velocity(sidebar, { width: "0px" }, { duration: 300 });
Velocity.js поддерживает очереди анимаций, что позволяет выстраивать прогрессивные сценарии:
Velocity(element, { opacity: 1 }, { duration: 200 });
Velocity(element, { translateY: 0 }, { duration: 300 });
Velocity(element, { scale: 1 }, { duration: 150 });
При прогрессивном улучшении очереди используются не для создания зависимости от JS, а для усиления уже существующего UX.
Одним из подходов является использование data-атрибутов для описания анимаций:
<div class="box" data-velocity="fadeIn" data-duration="300"></div>
document.querySelectorAll("[data-velocity]").forEach(el => {
Velocity(el, el.dataset.velocity, {
duration: Number(el.dataset.duration) || 300
});
});
Такой подход сохраняет HTML функциональным без JS, но добавляет слой поведения при его наличии.
Прогрессивное улучшение требует отложенной инициализации анимаций:
document.addEventListener("DOMContentLoaded", () => {
if (!window.Velocity) return;
const items = document.querySelectorAll(".item");
items.forEach((item, i) => {
Velocity(item, { opacity: 1, translateY: 0 }, {
delay: i * 50,
duration: 300
});
});
});
Здесь важно, что отсутствие Velocity.js не ломает интерфейс, а лишь убирает визуальную динамику.
Прогрессивное улучшение с Velocity.js можно представить как три слоя:
HTML + CSS без зависимостей
JavaScript без анимаций (логика)
Velocity.js как визуальное усиление
Разделение этих слоёв исключает смешение логики и визуального поведения.
Velocity.js уже оптимизирован для работы через
requestAnimationFrame, однако прогрессивное улучшение
требует дополнительного контроля:
Velocity(element, {
translateZ: 0,
translateX: "100px",
opacity: 1
});
Принудительное использование GPU-композитинга становится частью стратегии улучшения.
В сложных интерфейсах Velocity.js часто связывается с состояниями:
state.isOpen = true;
if (state.isOpen && window.Velocity) {
Velocity(modal, "fadeIn", { duration: 200 });
}
Прогрессивное улучшение здесь означает, что состояние приложения не зависит от анимации — анимация лишь отражает его.
Критические функции интерфейса должны работать без анимаций:
Velocity.js применяется только для:
Такой подход снижает риск деградации пользовательского опыта при отсутствии поддержки JS или при сбоях библиотеки.
Velocity.js позволяет точно задавать длительность и easing, что важно для прогрессивного улучшения:
Velocity(element, { opacity: 1 }, {
duration: 180,
easing: "ease-in-out"
});
Предсказуемость времени анимации делает интерфейс стабильным независимо от устройства и нагрузки.
В зрелых системах Velocity.js используется внутри изолированных модулей:
const Animation = {
show(el) {
if (!window.Velocity) return;
Velocity(el, "fadeIn", { duration: 250 });
}
};
Такая изоляция позволяет отключить или заменить библиотеку без изменения остальной логики приложения.