Чем отличаются transition и animation в CSS?
Вопрос
Чем transition отличается от @keyframes/animation, и какие свойства выгоднее анимировать с точки зрения производительности?
Короткий ответ
transition описывает плавный переход между двумя состояниями свойства и запускается только при изменении значения (например, по :hover или смене класса). @keyframes/animation описывает многошаговую последовательность состояний, которая может запускаться сама по себе, зацикливаться и повторяться без внешнего триггера. С точки зрения производительности выгоднее анимировать transform и opacity, а не свойства, вызывающие layout/paint.
Подробный ответ
transition реагирует на изменение значения CSS-свойства: было одно значение, стало другое — браузер плавно интерполирует между ними за заданное время. У transition всегда ровно две точки — начало и конец, без промежуточных шагов. Требует внешнего триггера: изменения класса, псевдокласса (:hover, :focus), инлайн-стиля через JS.
@keyframes + animation позволяют описать произвольное число промежуточных состояний (0%, 50%, 100% и т.д.) и не нуждаются во внешнем триггере — анимация может стартовать сама при применении класса и работать автономно. Дополнительные возможности, которых нет у transition:
animation-iteration-count— зацикливание (infiniteили конкретное число повторов).animation-direction—alternateдля движения туда-обратно.animation-fill-mode— сохранение состояния до/после анимации (forwards,backwards).animation-delay,animation-play-state— управление паузой и задержкой.
Производительность: браузер рендерит страницу через конвейер layout → paint → composite. Анимация свойств, влияющих на геометрию (width, height, top, left, margin), заставляет браузер каждый кадр пересчитывать layout всей затронутой части дерева — это дорого и может привести к "дёрганой" анимации (jank). Анимация transform (translate, scale, rotate) и opacity может выполняться только на этапе composite, часто на GPU, минуя layout и paint — это дешевле и плавнее. will-change: transform можно использовать как подсказку браузеру заранее подготовить отдельный композитный слой, но злоупотреблять им не стоит — лишние слои увеличивают потребление памяти.
Пример
/* transition: переход между состояниями по hover */
.button {
background-color: #3b82f6;
transform: translateY(0);
transition: background-color 0.2s ease, transform 0.2s ease;
}
.button:hover {
background-color: #2563eb;
transform: translateY(-2px);
}
/* animation: автономная зацикленная последовательность */
@keyframes pulse {
0% { transform: scale(1); opacity: 1; }
50% { transform: scale(1.05); opacity: 0.8; }
100% { transform: scale(1); opacity: 1; }
}
.badge {
animation: pulse 1.6s ease-in-out infinite;
}
/* плохо для производительности: анимируется layout-свойство */
.bad-example {
transition: width 0.3s ease, left 0.3s ease;
}
/* хорошо: тот же визуальный эффект через transform */
.good-example {
transition: transform 0.3s ease;
}
Дополнительные вопросы
- Что такое composite layer и почему
transform/opacityмогут анимироваться в обход layout и paint? - Как работает
animation-fill-mode: forwardsи зачем он нужен? - Чем
requestAnimationFrameв JS отличается от CSS-анимаций с точки зрения контроля и производительности?