Свойство transition в CSS: как создавать плавные эффекты и анимации
Разбираем, как работает свойство transition в CSS, рассматриваем его синтаксис, сценарии использования и типичные ошибки.
Свойство transition в CSS отвечает за плавное изменение стилей элементов и помогает создавать естественные визуальные эффекты при взаимодействии с интерфейсом. С его помощью обычные действия — наведение курсора, раскрытие меню или изменение цвета кнопки — выглядят мягко и динамично, делая интерфейс более живым и комфортным для пользователя.
Содержание
- Что такое CSS transition и зачем оно нужно
- Как работает transition: логика и принцип действия
- Синтаксис и составные части transition
- Использование transition с псевдоклассами
- Какие свойства можно анимировать
- Комбинирование transition с другими свойствами элемента
- Инструменты работы с transition
- Производительность и доступность
- Типичные ошибки при работе с transition
- Советы и лайфхаки
Что такое CSS transition и зачем оно нужно
Transition — это способ плавно менять значения CSS‑свойств, когда элемент переходит из одного состояния в другое: наведение, фокус, нажатие, открытие/закрытие и так далее. Вместо резкого «скачка» получается аккуратная плавная смена состояния.
Применение transition при разработке интерфейсов:
- улучшает UX (движение сообщает, что что‑то произошло);
- подчёркивает интерактивность элементов;
- делает интерфейсы цельными и современными;
- помогает экономно анимировать без сложных таймлайнов и ключевых кадров.
Как работает transition: логика и принцип действия
Transition запускается в тот момент, когда изменяется CSS-свойство, для которого задан переход. Чаще всего это происходит:
- при работе псевдоклассов: наведении мыши (: hover), фокусе (: focus/: focus-visible), клике (: active), переключении состояния чекбокса (: checked);
- при добавлении/удалении классов из JavaScript;
- при изменении инлайновых стилей или CSS‑переменных.
В отличие от сложных CSS-анимаций (animation), transition не требует ключевых кадров (@keyframes): браузер сам рассчитывает шаги перехода от исходного значения к итоговому и плавно воспроизводит их. Браузер рассчитывает промежуточные кадры между «было» и «стало» и за определённое время (transition-duration) меняет свойство (transition-property) по выбранной кривой ускорения (transition-timing-function), начиная после указанной задержки (transition-delay).
Однако если для анимации нужно больше фаз (ключевых точек), то используется свойство animation и его параметр @keyframes.
Синтаксис и составные части transition
Transition можно записать двумя способами: через отдельные свойства или сокращённую запись.
/* Здесь указаны отдельные свойства */
.element {
transition-property: background-color;
transition-duration: 0.3s;
transition-timing-function: ease-in-out;
transition-delay: 1s;
}
/* А это сокращённая запись */
.element {
transition: background-color 0.3s ease-in 1s;
}Сокращённая запись объединяет сразу четыре свойства:
- transition-property — какое свойство анимировать;
- transition-duration — сколько длится переход;
- transition-timing-function — как изменяется скорость (тип ускорения);
- transition-delay — задержка перед началом перехода.
Порядок значений в сокращённой записи: свойство, длительность, функция времени, задержка. Но обязательными являются только первые два параметра.
Часто есть необходимость совместить плавное изменение сразу нескольких свойств. Для этого удобно использовать сокращённую запись для каждого из свойств, разделяя их запятой.
.card {
transition: box-shadow 0.3s ease, transform 0.2s linear 0.1s;;
}Давайте теперь рассмотрим каждый параметр немного подробнее.
Свойство transition-property
Свойство transition-property определяет, какие CSS-свойства будут анимироваться. Можно указать конкретное свойство, несколько свойств через запятую или ключевое слово all для анимации всех изменяющихся свойств.
/* Анимируется только цвет фона */
.button {
transition-property: background-color;
}
/* Анимируются несколько свойств */
.card {
transition-property: transform, opacity, box-shadow;
}
/* Анимируются все изменяющиеся свойства */
.element {
transition-property: all;
}Использование значения all может быть удобным для быстрой проверки анимации, однако оно несёт определённые риски:
- Оно затрагивает все CSS-свойства элемента, включая те, изменение которых не предполагалось, что может привести к неожиданным визуальным артефактам.
- Анимация сразу всех свойств создаёт избыточную нагрузку на графический процессор (GPU), что нередко вызывает лаги (заметные задержки в отображении анимации) и ухудшение пользовательского опыта.
Чтобы избежать этих проблем, рекомендуется вместо all явно перечислять только те свойства, которые действительно должны анимироваться. Такой подход делает поведение анимации предсказуемым, контролируемым и производительным.
Свойство transition-duration
Свойство transition-duration задаёт продолжительность перехода. Это обязательный параметр — без него transition не сработает.
В качестве единиц измерения можно использовать как секунды (s), так и миллисекунды (ms). Однако рекомендуется выбрать один формат записи (например, всё в секундах), чтобы код выглядел единообразным.
.element {
transition-property: opacity;
transition-duration: 0.5s; /* Полсекунды */
}
.element-slow {
transition-property: transform;
transition-duration: 1500ms; /* Полторы секунды */
}
Скриншот: Google Chrome / Skillbox Media
Рекомендуемая длительность для большинства интерфейсных анимаций — от 150 до 400 миллисекунд (0.15s–0.4s). Слишком быстрые переходы (менее 100ms) могут быть незаметны, а слишком медленные (более 500ms) раздражают пользователей.
Свойство transition-timing-function
Свойство transition-timing-function управляет скоростью анимации на протяжении всей длительности перехода с использованием временных функций (кривых ускорения). Это позволяет сделать анимацию более естественной, ведь объекты в реальном мире не движутся с постоянной скоростью.
Визуально кривые ускорения можно представить так.

Скриншот: Google Chrome / Skillbox Media
Основные предустановленные функции:
- linear — постоянная скорость от начала до конца;
- ease — медленный старт, ускорение к середине, замедление к концу (по умолчанию);
- ease-in — медленный старт, ускорение к концу;
- ease-out — быстрый старт, замедление к концу;
- ease-in-out — медленный старт и конец, быстрая середина;
- steps — переход по шагам.
.button-linear {
transition: transform 0.3s linear;
}
.button-ease {
transition: opacity 0.3s ease-out;
}
Скриншот: Google Chrome / Skillbox Media
Для точной настройки используется функция cubic-bezier (), которая позволяет создавать собственные кривые ускорения.
.custom-timing {
transition: transform 0.4s cubic-bezier(0.68, -0.55, 0.265, 1.55);
}На иллюстрации ниже представлены три кнопки с идентичными параметрами анимации — единственное различие между ними заключается в используемых временных функциях.

Скриншот: Google Chrome / Skillbox Medi
Свойство transition-delay
Свойство transition-delay задаёт задержку перед началом анимации в секундах или миллисекундах. По умолчанию значение равно 0, и анимация начинается сразу.
.element {
transition-property: opacity;
transition-duration: 0.5s;
transition-delay: 0.2s; /* Задержка 200 миллисекунд */
}
Скриншот: Google Chrome / Skillbox Media
Задержка полезна для создания последовательных анимаций, когда элементы появляются один за другим.
/* Элементы появляются с нарастающей задержкой */
.list-item:nth-child(1) { transition-delay: 0s; }
.list-item:nth-child(2) { transition-delay: 0.1s; }
.list-item:nth-child(3) { transition-delay: 0.2s; }
Скриншот: Google Chrome / Skillbox Media
Также можно задать отрицательное значение transition-delay. Будет казаться, что переход уже частично прошёл: то есть визуально анимация «вступает» с середины или даже с конца, в зависимости от значения.
<div class="box default">Обычный (delay: 0s)</div>
<div class="box negative-delay">Отрицательная задержка (delay: -0.3s)</div>
<button id="toggle" type="button">Запустить / Сбросить</button>.box {
width: 350px;
margin: 10px 0;
padding: 20px;
background-color: #3498db;
color: white;
display: flex;
align-items: center;
justify-content: center;
border-radius: 4px;
/* Общее transition */
transition: transform 1s ease-in-out;
}
/* Начальное состояние при «сбросе» */
.box.reset {
transform: translateX(0);
}
/* Конечное состояние при «запуске» */
.box.active {
transform: translateX(200px);
}
/* Обычный элемент — без задержки */
.default {
transition-delay: 0s;
}
/* Элемент с отрицательной задержкой */
.negative-delay {
transition-delay: -0.3s; /* Анимация начнётся с середины */
}const toggleBtn = document.getElementById('toggle');
const boxes = document.querySelectorAll('.box');
toggleBtn.addEventListener('click', () => {
boxes.forEach(box => {
box.classList.toggle('active');
});
});
Скриншот: Google Chrome / Skillbox Media
Использование transition с псевдоклассами
Transition чаще всего используется с псевдоклассами, которые меняют состояние элемента, когда пользователь взаимодействует с элементом.
Это могут быть такие псевдоэлементы:
- : hover — курсор наведён на элемент;
- : focus и : focus-visible — элемент получил фокус (например, при переходе по Tab);
- : active — элемент активирован (например, реакция кнопки в момент нажатия).
Давайте посмотрим на код ниже:
.button {
background-color: #3498db;
color: white;
padding: 12px 24px;
border: none;
border-radius: 4px;
cursor: pointer;
transition: background-color 0.3s ease, transform 0.3s ease;
}
.button:hover {
background-color: #2980b9;
transform: translateY(-5px);
}
.button:active {
transform: translateY(0);
}Поведение кнопки должно быть таким: при : hover кнопка плавно изменяет цвет и немного поднимается. При клике (псевдокласс : active) кнопка возвращается в исходное положение.
Визуально это будет выглядеть так.

Скриншот: Google Chrome / Skillbox Media
Какие свойства можно анимировать
Не все CSS-свойства поддерживают плавную анимацию. Анимируемыми считаются те свойства, значения которых можно интерполировать — вычислить промежуточные значения между начальной точкой и конечной.
Свойства, которые можно анимировать:
- визуальные: opacity, color, background-color, box-shadow, filter, text-shadow;
- геометрия/позиция: transform (рекомендуется), height, width, margin, padding, top/left/bottom/right;
- прочее: letter-spacing, border-radius, outline-offset, clip-path и другие.
Свойства, которые переключаются мгновенно и не анимируются:
- display;
- visibility (но можно комбинировать с opacity);
- position;
- font-family.
Комбинирование transition с другими свойствами элемента
Свойство transition отлично работает вместе с другими свойствами, которые могут изменяться поэтапно (интерполируются). Свойства изменяют внешний вид элемента (поворот, масштаб, перемещение, ширина, цвет и так далее), а transition делает эти изменения плавными.
Однако для создания высокопроизводительных анимаций рекомендуется отдавать предпочтение свойствам opacity и transform: их изменение не приводит к перерисовке элемента и зачастую обрабатывается GPU, что значительно снижает нагрузку на браузер и улучшает производительность отображения.
То есть, например, вместо анимации свойств margin, padding или позиционирующих значений вроде top, right, bottom, left предпочтительнее использовать transform с функцией translate (). Для плавного изменения размеров элемента лучше задействовать transform: scale (), а не прямую анимацию width и height. А для эффектов появления или исчезновения идеально подходит opacity, так как оно не вызывает перерасчёта макета и работает эффективно даже при частых обновлениях.
Нередко это бывает критически важно для производительности, особенно на мобильных устройствах.
/* Медленно для браузера — вызывает перерисовку элемента */
.slow {
transition: width 0.3s, height 0.3s;
}
/* Быстро для браузера — обрабатывается GPU */
.fast {
transition: transform 0.3s, opacity 0.3s;
}Инструменты работы с transition
Использование transition вместе с: root
В CSS плавные переходы можно выстраивать не только с помощью конкретных значений, но и через переменные, задаваемые в : root. Такой подход упрощает масштабирование анимаций и обеспечивает единообразие кода.
Например, можно объявить в корне документа стандартные длительности и кривые ускорения:
:root {
--tr-fast: .15s;
--tr-base: .3s;
--tr-slow: .5s;
--ease-out: cubic-bezier(.22,.61,.36,1);
}Теперь любая кнопка, карточка или ссылка может использовать одинаковые значения без дублирования:
.button {
transition: background var(--tr-base) var(--ease-out);
}Это делает интерфейс более предсказуемым: все элементы анимируются в едином темпе и с одинаковой пластикой движения. Если дизайнер решит немного ускорить переходы, достаточно изменить значение переменной в одном месте — и всё обновится автоматически.
Использование transition вместе с: has
Ещё один инструмент для облегчения работы с transition — селектор : has ().
Он позволяет родителю реагировать на состояние потомков без использования JavaScript.
Например, при наведении на изображение можно плавно изменить тень карточки:
.card:has(img:hover) {
box-shadow: 0 16px 40px rgba(0, 0, 0, .2);
transition: box-shadow .3s;
}Такой подход делает код чище и уменьшает количество JS-обработчиков: взаимодействие описывается напрямую в CSS, декларативно.
С помощью : has () можно подсвечивать контейнеры форм при фокусе на поле (.field: has (input: focus)), анимировать карточки при наведении на их содержимое или визуально реагировать на выбор чекбокса без скриптов.
Использование transition вместе с JavaScript
Но всё же очень часто нужна логика, недостижимая одними селекторами. Тогда на помощь приходит JS. Самый распространённый сценарий: добавление и удаление класса, запускающего CSS-переход.
const modal = document.querySelector('.modal');
const openBtn = document.querySelector('.open-modal');
const closeBtn = document.querySelector('.close-modal');
openBtn.addEventListener('click', () => modal.classList.add('is-open'));
closeBtn.addEventListener('click', () => modal.classList.remove('is-open'));CSS-часть описывает только визуальный переход:
.modal {
opacity: 0;
pointer-events: none;
transition: opacity .3s ease;
}
.modal.is-open {
opacity: 1;
pointer-events: auto;
}Когда класс is-open появляется, свойство opacity меняется — и transition плавно делает модальное окно видимым. После закрытия — обратно.
Чтобы узнать, когда анимация закончится, удобно использовать событие transitionend:
modal.addEventListener('transitionend', (e) => {
if (e.propertyName === 'opacity' && !modal.classList.contains('is-open')) {
// Анимация завершена, можно удалить элемент из DOM
// modal.remove();
}
});Важно помнить:
- если свойство фактически не изменилось, событие transitionend не сработает;
- то же самое происходит, если элемент скрыт через display: none: браузер просто не будет анимировать.
Производительность и доступность
Чтобы переходы были плавными не только визуально, но и технически, важно учитывать несколько аспектов.
1. Производительность
Для производительности выгодно анимировать безопасные свойства — transform и opacity. Они не вызывают перерисовку макета и обрабатываются GPU. Также можно точечно использовать will-change, но важно удалять его после завершения эффекта, иначе оно может снижать производительность при массовом использовании.
2. Доступность
Не все пользователи комфортно воспринимают анимации. Некоторые испытывают головокружение, тошноту или просто отвлекаются от движения на экране — особенно при вестибулярных расстройствах или когнитивных особенностях. Чтобы сделать интерфейс более инклюзивным, современные браузеры позволяют учитывать системные настройки пользователя через медиазапрос prefers-reduced-motion.
CSS-медиазапрос prefers-reduced-motion помогает корректно учитывать их настройки:
@media (prefers-reduced-motion: reduce) {
* {
transition-duration: .01ms !important;
}
}Так мы снижаем нагрузку на зрение и делаем интерфейс комфортным для всех.
Важно помнить, что функциональные анимации, например индикатор загрузки или визуальная обратная связь при ошибке, влияют на понимание происходящего на странице. Поэтому их следует оставить, сделав максимально статичными или мгновенными. Отключить в этом случае можно косметические анимации, такие как плавное появление, покачивание.
Типичные ошибки при работе с transition
Даже простые переходы могут не сработать или выглядеть некорректно из-за мелких ошибок. Минимальная рабочая запись — это свойство и длительность.
1. Не указана длительность (transition-duration)
Без длительности переход не запустится: по умолчанию длительность анимации равна нулю. Следующий пример не анимирует цвет, потому что время не задано:
/* Плохо: длительность не задана → анимации нет */
.box { transition: opacity; }
/* Хорошо: есть длительность (и кривая по желанию) */
.box { transition: opacity .3s ease; }
.box:hover { opacity: .6; }2. Анимация свойства display
Свойство display не участвует в переходах — оно дискретное (не имеет промежуточных состояний).
Поэтому следующий код не сработает:
.box {
display: none;
transition: display 0.3s; /* Не сработает */
}Вместо этого анимируйте opacity и (или) transform, а display меняйте через JS только для скрытия после завершения перехода:
.box {
opacity: 0;
transform: translateY(-10px);
transition: opacity 0.3s, transform 0.3s;
}
.box.visible {
opacity: 1;
transform: translateY(0);
}3. Переход задан не тому элементу
Переход описывается на самом элементе, значения которого меняются. Если мы вешаем transition на родителя, а меняем стиль у потомка — анимации не будет.
/* Плохо: transition на контейнере, а меняется фон у .card */
.container { transition: background .3s; }
.card:hover { background: #ffd; }
/* Хорошо: transition на .card, именно у неё меняется background */
.card { transition: background .3s; }
.card:hover { background: #ffd; }4. transition-property: all без необходимости
Значение all выглядит удобно, но часто приводит к лагам и визуальным багам: браузер пытается анимировать абсолютно все свойства (включая те, которые не должны меняться).
.card {
transition: all 0.3s ease; /* Не оптимально */
}Лучше явно указать нужные свойства:
.card {
transition: transform 0.3s ease, box-shadow 0.3s ease;
}5. Не учитывается каскад и побочные анимации
Если вы указали несколько свойств в transition, они все будут анимироваться при изменении любого из них.
.box {
transition: color 0.3s, background 0.3s;
}
.box:hover {
background: #333;
}Даже если изменилось только свойство background, браузер будет готов анимировать и color, а это лишние перерисовки.
Поэтому важно указывать именно те свойства, которые действительно должны плавно меняться в данном компоненте.
.box {
transition: background 0.3s;
}
.box:hover {
background: #333;
}Советы и лайфхаки
- Используйте transition только для небольших изменений. Для сложных многоступенчатых анимаций — используйте animation.
- Плавную анимацию свойства font-weight поддерживают только вариативные шрифты, которые могут содержать множество промежуточных точек начертаний. Обычные шрифты имеют ограниченный набор начертаний, что не позволяет браузеру плавно перемещаться между ними, поэтому анимация происходит скачками.
- Оптимизируйте производительность: лучше всего анимируются opacity и transform (они не вызывают перерасчёт layout).
- Для появления/скрытия используйте opacity + pointer-events.
.tooltip {
opacity: 0;
pointer-events: none;
transition: opacity 0.3s;
}
.tooltip.visible {
opacity: 1;
pointer-events: auto;
}- В больших проектах используйте переменные CSS для унификации переходов.
- В компонентных проектах, где требуется переиспользование разных анимаций для разных блоков, можно выносить transition в отдельные utility-классы, чтобы добавлять и убирать их по необходимости.
Больше интересного про код — в нашем телеграм-канале. Подписывайтесь!