Порядок применения трансформаций

В системе анимации Velocity.js трансформации подчиняются не только порядку объявления свойств, но и фундаментальной модели композиции CSS-трансформаций, основанной на матричном умножении. Любое визуальное преобразование элемента в итоге сводится к построению итоговой матрицы transform, и именно порядок операций внутри этой матрицы определяет конечный результат.


Каждая трансформация в CSS (и, соответственно, в Velocity.js) представляется как матрица. При применении нескольких трансформаций они не складываются, а перемножаются.

Ключевая особенность:

  • умножение матриц не коммутативно
  • порядок операций критически влияет на результат

Если заданы трансформации:

  • перемещение (translate)
  • вращение (rotate)
  • масштабирование (scale)

то итоговая матрица формируется как произведение:

M = T × R × S

Но визуально применяется справа налево:

  • сначала применяется scale
  • затем rotate
  • затем translate

Это означает, что «поздние» операции в записи оказываются «ближе» к объекту в пространстве преобразований.


Базовый порядок внутри CSS transform

В стандартной модели CSS:

transform: translate() rotate() scale();

фактическая последовательность вычислений:

  1. scale
  2. rotate
  3. translate

Из этого следует важное поведение:

  • масштабирование влияет на систему координат вращения
  • вращение изменяет направление последующего смещения
  • смещение всегда происходит в уже преобразованной системе координат

Поведение в Velocity.js при работе с transform

В Velocity.js трансформации могут задаваться двумя основными способами:

1. Строковый CSS-формат

Velocity(element, {
  transform: "translateX(100px) rotate(45deg) scale(1.5)"
});

В этом случае:

  • порядок строго соответствует CSS
  • движок браузера самостоятельно формирует матрицу
  • Velocity.js передаёт строку без перестановки операций

Итоговое поведение определяется браузером, а не библиотекой.


2. Объектный формат transform-полей

Velocity(element, {
  translateX: 100,
  rotateZ: 45,
  scale: 1.5
});

Здесь появляется важная особенность:

  • Velocity.js нормализует трансформации
  • затем собирает их в единый transform
  • порядок определяется внутренним алгоритмом сборки

Типичный порядок сборки:

  1. translate
  2. rotate
  3. scale

Однако визуально это всё равно интерпретируется как матричное произведение, где итоговый эффект эквивалентен CSS-поведению.


Почему порядок трансформаций критичен

Рассмотрим поведение на примерах.

Масштабирование и смещение

Если задать:

translateX(100px) scale(2)

то результат будет отличаться от:

scale(2) translateX(100px)

Пояснение:

  • при scale → translate: смещение тоже масштабируется
  • при translate → scale: сначала происходит перенос, затем масштабирование всей системы координат

Итог:

  • расстояния «раздуваются» или «сжимаются» в зависимости от порядка

Вращение и смещение

Комбинация:

translateX(100px) rotate(90deg)

даёт:

  • смещение по оси X
  • затем поворот вокруг origin

Но:

rotate(90deg) translateX(100px)

даёт:

  • сначала поворот системы координат
  • затем смещение уже по повернутой оси (фактически по Y)

Это одно из самых частых источников неожиданных визуальных эффектов.


Роль transform-origin

Порядок трансформаций тесно связан с точкой опоры:

  • transform-origin определяет центр вращения и масштабирования
  • изменения порядка трансформаций меняют траекторию относительно этой точки

Пример влияния:

  • при rotate → translate элемент «уезжает» по дуге
  • при translate → rotate элемент вращается на месте после смещения

transform-origin не меняет порядок операций, но меняет геометрию каждой из них.


Внутренний пайплайн Velocity.js

При анимации transform в Velocity.js происходит несколько этапов:

1. Парсинг значений

  • выделение отдельных transform-свойств
  • нормализация единиц (px, deg, %)

2. Интерполяция

  • вычисление промежуточных значений
  • применение easing-функций

3. Сборка transform-строки или матрицы

  • объединение всех трансформаций
  • приведение к итоговому CSS-формату

4. Применение к элементу

  • запись в style.transform
  • GPU-ускорение при возможности

На этапе сборки происходит ключевая фиксация порядка.


Особенности комбинирования нескольких анимаций

При одновременной анимации нескольких transform-свойств:

  • Velocity.js может объединять их в один tween
  • либо разбивать на отдельные слои интерполяции

Например:

Velocity(element, {
  translateX: 200,
  rotateZ: 360
}, {
  duration: 1000
});

Внутренне:

  • оба свойства интерполируются параллельно
  • итоговый transform собирается на каждом кадре
  • порядок сборки фиксирован на этапе инициализации

Композиция нескольких Velocity-анимаций

При последовательных вызовах:

Velocity(element, { translateX: 100 });
Velocity(element, { rotateZ: 45 });

поведение зависит от очереди:

  • если очередь включена, трансформации накладываются
  • если очередь отключена, возможна перезапись transform

Это важно, поскольку порядок не только внутри transform, но и между анимациями влияет на итоговую матрицу.


Перезапись transform и накопление состояния

Критический момент:

  • transform в DOM не хранит историю операций
  • хранится только итоговая строка или матрица

Следствия:

  • новая анимация может уничтожить предыдущие трансформации
  • Velocity.js должен учитывать текущий computed style
  • иначе порядок операций теряется

Поэтому библиотека часто читает текущее состояние перед стартом анимации.


Практическое следствие матричного порядка

Основные закономерности:

  • translate влияет на позицию системы координат
  • rotate изменяет направление всех последующих операций
  • scale изменяет размер системы координат, включая смещения

Из этого вытекает:

  • порядок transform определяет траекторию движения
  • одинаковые значения могут давать разные анимации
  • композиция всегда нелинейна

Итоговая модель восприятия порядка

В контексте Velocity.js корректнее рассматривать transform не как список операций, а как последовательность матричных преобразований:

  • каждая операция меняет пространство
  • следующая операция работает уже в изменённой системе координат
  • финальный результат — произведение всех преобразований

Именно поэтому изменение порядка даже двух свойств полностью меняет поведение анимации без изменения числовых параметров.