Анимация custom properties

CSS custom properties (переменные --var) позволяют выносить динамические значения из стилей и управлять ими через JavaScript. В связке с Motion One они становятся полноценными анимируемыми параметрами, которые можно использовать для создания гибких интерфейсных эффектов, зависящих от состояния приложения, скролла, пользовательского ввода и вычисляемых значений.

Motion One поддерживает анимацию custom properties через стандартный механизм CSS-переменных без необходимости дополнительной конфигурации, при условии корректного задания начальных значений и типов.


Базовый принцип анимации CSS переменных

CSS custom properties не имеют строгого типа по умолчанию. Браузер интерпретирует их как строки, что ограничивает возможность интерполяции. Для анимации требуется явно задать контекст числового или цветового значения.

.box {
  --x: 0px;
  transform: translateX(var(--x));
}
import { animate } from "motion";

animate(".box", {
  "--x": "200px"
});

Motion One автоматически интерполирует числовые значения, если начальное и конечное состояние совместимы по типу.


Числовые custom properties

Наиболее распространённый сценарий — анимация чисел, используемых внутри transform, opacity-подобных эффектов или сложных вычислений.

.card {
  --scale: 1;
  transform: scale(var(--scale));
}
animate(".card", {
  "--scale": 1.2
});

При анимации числовых значений Motion One:

  • определяет начальное значение из computed styles
  • вычисляет промежуточные значения
  • обновляет CSS переменную на каждом кадре

Единицы измерения и их важность

CSS custom properties требуют явного указания единиц измерения, если значение не безразмерное. Несоответствие единиц блокирует интерполяцию.

Корректный пример:

animate(".panel", {
  "--offset": "300px"
});

Некорректный вариант:

animate(".panel", {
  "--offset": 300
});

В последнем случае значение будет интерпретировано неоднозначно, что может привести к отсутствию плавной анимации.


Анимация цветов через custom properties

CSS переменные могут хранить цвета в любом валидном формате: rgb, rgba, hsl, hex. Motion One выполняет интерполяцию цветов при совместимых форматах.

.button {
  --color: rgb(0, 0, 0);
  background: var(--color);
}
animate(".button", {
  "--color": "rgb(255, 100, 0)"
});

Для стабильной интерполяции предпочтительно использовать одинаковые цветовые модели на старте и в целевом состоянии.


Использование custom properties внутри сложных трансформаций

Custom properties часто применяются как параметры внутри transform, что позволяет строить сложные анимации без прямого управления transform через JavaScript.

.avatar {
  --x: 0px;
  --y: 0px;

  transform: translate3d(var(--x), var(--y), 0);
}
animate(".avatar", {
  "--x": "120px",
  "--y": "-80px"
});

Такой подход обеспечивает:

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

Анимация через keyframes

Motion One поддерживает keyframes для custom properties так же, как и для стандартных CSS свойств.

animate(".box", {
  "--progress": [0, 1]
}, {
  duration: 1
});

Применение в CSS:

.box {
  --progress: 0;
  opacity: var(--progress);
}

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


Синхронизация нескольких custom properties

Одновременная анимация нескольких переменных позволяет создавать согласованные эффекты движения и трансформации.

animate(".panel", {
  "--x": ["0px", "200px"],
  "--opacity": [0, 1],
  "--scale": [0.8, 1]
}, {
  duration: 0.8,
  easing: "ease-out"
});

В этом случае Motion One синхронно обновляет все свойства в одном анимационном тикe, что гарантирует согласованность визуального результата.


Интеграция с easing-функциями

Custom properties полностью совместимы с системами easing Motion One. Это позволяет управлять динамикой изменения значений без изменения логики вычислений.

animate(".dot", {
  "--x": "400px"
}, {
  easing: "ease-in-out",
  duration: 1.5
});

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


Динамическое управление через JavaScript

Custom properties могут быть привязаны к состоянию приложения и обновляться программно.

const state = { progress: 0 };

function update(value) {
  state.progress = value;

  animate(".loader", {
    "--progress": value
  }, {
    duration: 0
  });
}

При duration: 0 значение обновляется мгновенно, превращая анимацию в реактивное управление стилями.


Связь custom properties с анимацией скролла

Motion One позволяет использовать scroll-driven анимации, где CSS переменные становятся посредником между скроллом и визуальными эффектами.

import { animate, scroll } from "motion";

scroll(
  animate(".hero", {
    "--blur": ["0px", "10px"],
    "--scale": [1, 1.2]
  }),
  {
    target: document.querySelector(".hero"),
    offset: ["start start", "end start"]
  }
);

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


Производительность при анимации custom properties

Анимация CSS переменных выполняется на стороне главного потока браузера, но Motion One минимизирует накладные расходы за счёт:

  • батчинга обновлений
  • использования requestAnimationFrame
  • избегания лишних reflow при корректной структуре CSS

Рекомендуемые практики:

  • использовать transform и opacity внутри custom properties
  • избегать анимации свойств, вызывающих layout (например, width/height напрямую через переменные)
  • группировать переменные, относящиеся к одному визуальному эффекту

Типизация и стабильность интерполяции

Ключевой аспект работы с custom properties — стабильность типа значения.

Поддерживаемые категории:

  • числа (0, 1, 0.5)
  • длины (px, rem, %)
  • цвета (rgb, hsl, hex)
  • углы (deg, rad)
  • комплексные строки при совпадающей структуре

Нестабильные сценарии:

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

Анимация через вычисляемые значения

Custom properties часто используются как промежуточный слой для вычислений в CSS.

.progress {
  --value: 0;
  --angle: calc(var(--value) * 3.6deg);

  transform: rotate(var(--angle));
}
animate(".progress", {
  "--value": 100
});

Такой подход позволяет делегировать вычисления CSS, оставляя JavaScript только управление состоянием.


Композиция эффектов через несколько переменных

Custom properties позволяют создавать сложные композиции без увеличения сложности JS-логики.

.element {
  --tx: 0px;
  --ty: 0px;
  --blur: 0px;
  --opacity: 1;

  transform: translate(var(--tx), var(--ty));
  filter: blur(var(--blur));
  opacity: var(--opacity);
}
animate(".element", {
  "--tx": "150px",
  "--ty": "80px",
  "--blur": "6px",
  "--opacity": 0.5
});

Такой подход обеспечивает масштабируемость анимационных систем в интерфейсах с высокой плотностью взаимодействий.


Интеграция с состояниями интерфейса

Custom properties удобно использовать как слой между состояниями UI и визуальными эффектами.

function setActive(isActive) {
  animate(".menu", {
    "--active": isActive ? 1 : 0
  }, {
    duration: 0.3
  });
}
.menu {
  opacity: calc(0.5 + var(--active) * 0.5);
  transform: scale(calc(1 + var(--active) * 0.05));
}

Такой паттерн снижает связанность логики и визуальной части.


Ограничения и особенности поведения

При работе с custom properties в Motion One следует учитывать:

  • отсутствие начального значения в CSS приводит к невозможности интерполяции
  • строковые значения без структуры не анимируются
  • сложные выражения calc() должны быть согласованы по типам
  • наследование переменных может влиять на результат анимации

Стабильность достигается за счёт явного объявления всех переменных на уровне элемента.


Использование custom properties как API слоя

В архитектуре интерфейсов CSS переменные часто выступают как публичный API визуального слоя.

.component {
  --x: 0px;
  --y: 0px;
  --opacity: 1;
}

JavaScript взаимодействует только с этим API:

animate(".component", {
  "--x": "100px",
  "--opacity": 0.8
});

Такой подход позволяет:

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