Типографические эффекты в Motion One строятся вокруг манипуляции отдельными символами или группами символов с использованием анимации свойств transform, opacity, filter и spacing. Основной принцип заключается в том, что текст рассматривается не как единый блок, а как набор независимых элементов, каждый из которых может изменяться во времени с собственной задержкой, длительностью и функцией плавности.
Motion One предоставляет низкоуровневый API для анимации
DOM-элементов через функцию animate. Текстовые эффекты не
являются встроенной абстракцией, поэтому типографика реализуется через
ручное разбиение строки на элементы.
Базовый пример анимации одного текстового блока:
import { animate } from "motion";
animate(
"#title",
{ opacity: [0, 1], y: [20, 0] },
{ duration: 0.6, easing: "ease-out" }
);
Такой подход работает только с целым элементом. Для создания типографических эффектов текст предварительно сегментируется.
Основой большинства эффектов является разбиение строки на
<span>-элементы, каждый из которых содержит один
символ.
const el = document.querySelector("#text");
const text = el.textContent;
el.textContent = "";
const chars = text.split("");
chars.forEach(char => {
const span = document.createElement("span");
span.textContent = char;
span.style.display = "inline-block";
el.appendChild(span);
});
Каждый символ становится независимым DOM-узлом, что позволяет применять анимацию индивидуально.
После этого можно анимировать каждый символ через Motion One.
import { animate } from "motion";
document.querySelectorAll("#text span").forEach((span, i) => {
animate(
span,
{ opacity: [0, 1], y: [10, 0] },
{ delay: i * 0.03, duration: 0.4 }
);
});
Ключевой параметр здесь — delay, создающий эффект
последовательного появления.
Stagger-эффект формирует ритмическое появление символов, слов или строк. В Motion One нет отдельного stagger-API как в некоторых библиотеках, но эффект достигается через вычисляемую задержку.
const letters = document.querySelectorAll(".title span");
letters.forEach((letter, index) => {
animate(
letter,
{ opacity: [0, 1], scale: [0.8, 1] },
{
delay: index * 0.05,
duration: 0.5
}
);
});
Для более сложной логики используется математическая модуляция задержки:
const waveDelay = (i, total) => {
return Math.sin(i / total * Math.PI) * 0.2;
};
letters.forEach((letter, i) => {
animate(
letter,
{ y: [20, 0], opacity: [0, 1] },
{
delay: waveDelay(i, letters.length),
duration: 0.6
}
);
});
Такой подход позволяет формировать нелинейные паттерны появления текста.
Эффект имитации набора текста строится на последовательном изменении прозрачности символов или постепенном добавлении DOM-элементов.
Вариант с заранее подготовленными символами:
const chars = document.querySelectorAll("#typewriter span");
chars.forEach((char, i) => {
animate(
char,
{ opacity: [0, 1] },
{
delay: i * 0.08,
duration: 0.01
}
);
});
Более динамическая версия без предварительной разметки:
const el = document.querySelector("#typewriter");
const text = el.textContent;
el.textContent = "";
let i = 0;
function type() {
if (i < text.length) {
const span = document.createElement("span");
span.textContent = text[i];
el.appendChild(span);
animate(span, { opacity: [0, 1], y: [5, 0] }, { duration: 0.2 });
i++;
requestAnimationFrame(type);
}
}
type();
Подобный подход позволяет сочетать DOM-мутацию и анимацию в реальном времени.
Типографические эффекты часто включают работу с фильтрами. Размытие позволяет создавать эффект фокуса или проявления текста.
document.querySelectorAll(".blur-text span").forEach((span, i) => {
animate(
span,
{
opacity: [0, 1],
filter: ["blur(10px)", "blur(0px)"]
},
{
delay: i * 0.04,
duration: 0.6
}
);
});
Комбинация blur и transform создаёт эффект “проявления из глубины”:
animate(
span,
{
opacity: [0, 1],
scale: [1.1, 1],
filter: ["blur(8px)", "blur(0px)"]
},
{ duration: 0.7 }
);
Манипуляции межбуквенным расстоянием используются для создания эффекта сборки текста из хаоса.
animate(
"#headline",
{
letterSpacing: ["0.5em", "0em"],
opacity: [0, 1]
},
{
duration: 0.8,
easing: "ease-out"
}
);
В более сложных сценариях letter-spacing комбинируется с разбиением на символы:
document.querySelectorAll("#headline span").forEach((span, i) => {
animate(
span,
{
transform: ["translateX(10px)", "translateX(0px)"],
opacity: [0, 1]
},
{
delay: i * 0.02,
duration: 0.4
}
);
});
Такая комбинация создаёт эффект «сжатия» текста в финальную форму.
Волновая анимация строится на синусоидальном распределении задержек или смещений. Каждый символ получает уникальное смещение по оси Y или фазовую задержку.
const letters = document.querySelectorAll(".wave span");
letters.forEach((letter, i) => {
const offset = Math.sin(i * 0.5) * 10;
animate(
letter,
{
y: [offset + 20, offset],
opacity: [0, 1]
},
{
delay: i * 0.02,
duration: 0.5
}
);
});
Более выраженный эффект достигается при использовании временной функции внутри интервала:
letters.forEach((letter, i) => {
animate(
letter,
{
y: [30, 0]
},
{
delay: i * 0.03,
duration: 0.6,
easing: t => Math.sin(t * Math.PI)
}
);
});
Такой тип easing формирует нелинейное движение, усиливающее ощущение волны.
Motion One поддерживает scroll-based анимации через
inView и scroll утилиты. Типографические
эффекты часто активируются при попадании текста в область видимости.
import { inView, animate } from "motion";
inView("#section-title", ({ target }) => {
target.querySelectorAll("span").forEach((span, i) => {
animate(
span,
{ opacity: [0, 1], y: [15, 0] },
{ delay: i * 0.03, duration: 0.5 }
);
});
});
Scroll-триггеры позволяют избегать лишних вычислений до момента появления элемента.
Для более точного контроля используется scroll
прогресс:
import { scroll, animate } from "motion";
scroll(({ y }) => {
const progress = y.progress;
document.querySelectorAll("#text span").forEach((span, i) => {
span.style.opacity = Math.min(1, Math.max(0, progress * 2 - i * 0.02));
});
});
Здесь анимация напрямую зависит от позиции прокрутки.
На практике типографические эффекты редко существуют изолированно. Чаще всего применяется комбинация нескольких техник: stagger, blur, transform и opacity.
document.querySelectorAll(".combo span").forEach((span, i) => {
animate(
span,
{
opacity: [0, 1],
y: [20, 0],
filter: ["blur(6px)", "blur(0px)"],
scale: [0.95, 1]
},
{
delay: i * 0.025,
duration: 0.6
}
);
});
Сочетание параметров формирует многослойную динамику появления текста, где каждый символ проходит несколько стадий трансформации.
Анимация большого количества символов требует внимания к производительности. Основные ограничения связаны с количеством DOM-элементов и частотой обновлений.
Оптимизационные подходы включают:
Использование transform и opacity как
основных анимируемых свойств, поскольку они не вызывают layout
recalculation.
Снижение количества DOM-узлов через группировку символов в слова:
const words = text.split(" ");
words.forEach(word => {
const wrapper = document.createElement("span");
wrapper.className = "word";
wrapper.textContent = word;
el.appendChild(wrapper);
});
Анимация слов вместо символов снижает нагрузку на рендеринг.
Применение will-change для подготовки слоя
композитинга:
span {
will-change: transform, opacity;
}
Минимизация количества одновременных активных анимаций также влияет на стабильность кадровой частоты.
Типографические эффекты в Motion One формируются на основе комбинации DOM-декомпозиции, временных задержек и анимации базовых визуальных свойств. Гибкость библиотеки позволяет строить как простые эффекты появления, так и сложные многослойные текстовые сцены с нелинейной динамикой и привязкой к пользовательскому взаимодействию.