transition: плавные переходы

transition — CSS-свойство, которое создаёт плавный переход между двумя состояниями элемента при изменении CSS-свойств (обычно по :hover, :focus, :checked, добавлении класса).

Зачем нужно

Без transition изменение свойства происходит мгновенно — элемент «перепрыгивает» в новое состояние. Transition добавляет анимацию перехода, делая интерфейс более плавным и приятным. Это самый простой и производительный способ анимации в CSS — без единой строки JavaScript и без @keyframes.

Где используется

  • Hover-эффекты на кнопках, ссылках, карточках
  • Плавное появление/скрытие элементов (opacity)
  • Изменение цвета, размера, позиции по взаимодействию
  • Плавное раскрытие аккордеонов и меню
  • Анимация фокуса на инпутах
  • Смена темы (светлая/тёмная)
  • Анимация tooltip
  • Анимация иконок и стрелок

Предпосылки

Отдельные свойства

.element {
  /* Какие свойства анимировать */
  transition-property: background-color, transform, opacity;

  /* Длительность перехода */
  transition-duration: 300ms;

  /* Функция плавности */
  transition-timing-function: ease;

  /* Задержка перед началом */
  transition-delay: 0s;
}

transition-property

.element {
  /* Конкретные свойства */
  transition-property: opacity, transform;

  /* Все анимируемые свойства */
  transition-property: all;

  /* Отключить переходы */
  transition-property: none;
}

all удобен, но снижает контроль — может анимировать свойства, которые не нужно. Лучше указывать конкретные свойства.

transition-duration

.element {
  transition-duration: 300ms;   /* Миллисекунды */
  transition-duration: 0.3s;    /* Секунды */
  transition-duration: 0s;      /* Мгновенно (по умолчанию) */
}

Рекомендуемые значения:

  • 100–150ms — микро-взаимодействия (hover на иконке)
  • 200–300ms — стандартные переходы (кнопки, карточки)
  • 300–500ms — крупные элементы (модальные окна, панели)

transition-timing-function

.element {
  /* Встроенные функции */
  transition-timing-function: ease;        /* По умолчанию: медленно → быстро → медленно */
  transition-timing-function: linear;      /* Равномерно */
  transition-timing-function: ease-in;     /* Медленный старт */
  transition-timing-function: ease-out;    /* Медленное завершение */
  transition-timing-function: ease-in-out; /* Медленные старт и конец */

  /* Кастомная кривая Безье */
  transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); /* Material Design */

  /* Шаговая функция */
  transition-timing-function: steps(4, end);
}

transition-delay

.element {
  transition-delay: 0s;      /* Без задержки */
  transition-delay: 200ms;   /* Задержка 200мс */
  transition-delay: -100ms;  /* Начать «с середины» анимации */
}

Сокращённая запись (shorthand)

.element {
  /* property duration timing-function delay */
  transition: background-color 300ms ease 0s;

  /* Минимум: свойство и длительность */
  transition: opacity 200ms;

  /* Несколько переходов через запятую */
  transition:
    background-color 200ms ease,
    transform 300ms ease-out,
    box-shadow 250ms ease;

  /* Все свойства */
  transition: all 300ms ease;
}

Какие свойства можно анимировать

Анимируются хорошо (на GPU)

/* Самые производительные — compositing only */
.element {
  transition: opacity 300ms ease;
  transition: transform 300ms ease;
}

Анимируются нормально

.element {
  /* Цвета */
  transition: color 200ms, background-color 200ms, border-color 200ms;

  /* Размеры (вызывают reflow — осторожно) */
  transition: width 300ms, height 300ms, padding 300ms;

  /* Тени */
  transition: box-shadow 250ms;
}

Не анимируются

  • display — нет промежуточных значений
  • font-family — нельзя плавно сменить шрифт
  • background-image — между url нельзя (но можно между градиентами)
  • position — значения static, relative и т.д. дискретны

Практические примеры

Hover на кнопке

.button {
  background-color: #007bff;
  color: white;
  padding: 10px 24px;
  border: none;
  border-radius: 6px;
  cursor: pointer;
  transition:
    background-color 200ms ease,
    transform 150ms ease;
}

.button:hover {
  background-color: #0056b3;
  transform: translateY(-2px);
}

.button:active {
  transform: translateY(0);
}

Карточка с тенью

.card {
  background: white;
  border-radius: 12px;
  padding: 24px;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
  transition:
    box-shadow 300ms ease,
    transform 300ms ease;
}

.card:hover {
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.15);
  transform: translateY(-4px);
}

Плавный фокус поля формы

.input {
  border: 2px solid #ddd;
  border-radius: 4px;
  padding: 8px 12px;
  outline: none;
  transition: border-color 0.2s ease, box-shadow 0.2s ease;
}

.input:focus {
  border-color: #007bff;
  box-shadow: 0 0 0 3px rgba(0, 123, 255, 0.25);
}

Плавное появление через opacity

.fade-element {
  opacity: 0;
  transform: translateY(10px);
  transition:
    opacity 400ms ease,
    transform 400ms ease;
}

.fade-element.visible {
  opacity: 1;
  transform: translateY(0);
}

Подчёркивание ссылки

.link {
  position: relative;
  text-decoration: none;
  color: #007bff;
}

.link::after {
  content: "";
  position: absolute;
  bottom: -2px;
  left: 0;
  width: 0;
  height: 2px;
  background: currentColor;
  transition: width 300ms ease;
}

.link:hover::after {
  width: 100%;
}

Плавное появление tooltip

.tooltip {
  opacity: 0;
  transition: opacity 0.2s ease;
}
.tooltip.visible {
  opacity: 1;
}

Производительность

/* ХОРОШО — только composite-свойства */
.element {
  transition: transform 300ms ease, opacity 300ms ease;
}

/* ПЛОХО — вызывает layout/reflow */
.element {
  transition: width 300ms, height 300ms, top 300ms, left 300ms;
}

/* СОВЕТ: вместо width/height анимируйте transform: scale */
.element {
  transition: transform 300ms ease;
}
.element:hover {
  transform: scale(1.05);
}

will-change — подсказка браузеру для оптимизации:

.element {
  will-change: transform, opacity;
  transition: transform 300ms ease;
}

Не злоупотребляйте — используйте только для элементов, которые точно будут анимироваться.

Частые ошибки

  1. Transition на display: nonedisplay: block — не работает:
    /* НЕ сработает */
    .element {
      display: none;
      transition: opacity 300ms;
    }
    .element.visible {
      display: block;
      opacity: 1;
    }
    /* Используйте opacity + visibility вместо display */
    
  2. Transition в состоянии :hover, а не в базовом:
    /* ОШИБКА — анимация только при наведении, не при уходе */
    .element:hover {
      transition: background 200ms;
      background: red;
    }
    /* ПРАВИЛЬНО — transition в базовом состоянии */
    .element {
      transition: background 200ms;
    }
    .element:hover {
      background: red;
    }
    
  3. transition: all анимирует лишнее — указывайте конкретные свойства
  4. Слишком долгая анимация — более 500ms воспринимается как «тормоза»
  5. Конфликт с animation — если оба свойства применены к одному CSS-property, animation выигрывает

Практика

  • Создать кнопку с плавным hover (цвет + сдвиг вверх)
  • Сделать карточку с анимированной тенью при наведении
  • Реализовать подчёркивание ссылки через ::after + transition
  • Сделать плавное появление элемента (opacity + transform)
  • Попробовать разные timing-function и сравнить

Связанные темы

Ресурсы