Анимация в jQuery: fadeIn, slideToggle, animate, очередь и stop

Анимация в jQuery: fadeIn, slideToggle, animate, очередь и stop Полезное

Анимация в jQuery — это набор методов модуля effects (fadeIn, slideToggle, animate и другие), которые плавно меняют числовые CSS-свойства элемента во времени и выстраивают такие изменения в очередь.

Сразу про контекст 2026 года. jQuery жив и поддерживается, в 2026 году вышла ветка jQuery 4, но для нового кода анимацию обычно делают без библиотеки: на CSS transitions или через Web Animations API. Поэтому ниже — как устроены эффекты jQuery (чтобы уверенно поддерживать существующий код) и нативный аналог для каждого сценария.

Минимальный рабочий пример

Сохраните файл jquery.min.js (версии 3.7 или 4.x, полная сборка, не slim) рядом со страницей и откройте в браузере:

<!DOCTYPE html>
<html lang="ru">
<head>
  <meta charset="utf-8">
  <style>
    #panel { width: 240px; padding: 12px; background: #dbeafe; }
  </style>
</head>
<body>
  <button id="toggle">Показать или скрыть</button>
  <div id="panel">Текст панели</div>

  <script src="jquery.min.js"></script>
  <script>
    $("#toggle").on("click", function () {
      $("#panel").stop(true).slideToggle(400, function () {
        console.log("Готово, видима:", $(this).is(":visible"));
      });
    });
  </script>
</body>
</html>

Что произойдет: по первому клику панель за 400 мс «закатится» вверх, в консоли появится Готово, видима: false. По второму — раскроется обратно, в консоли Готово, видима: true. Вызов stop(true) нужен, чтобы частые клики не копили очередь анимаций — подробнее ниже.

Если в консоли ошибка slideToggle is not a function, подключена slim-сборка: в ней нет модуля effects, и все методы анимации отсутствуют.

Встроенные эффекты: что меняет каждый

У всех встроенных эффектов одинаковая сигнатура: длительность, функция сглаживания (easing) и колбэк по завершении. Длительность — число в миллисекундах или строка: "fast" = 200 мс, "slow" = 600 мс, без аргумента — 400 мс.

Метод Какие свойства анимирует Итоговое состояние
hide(ms) / show(ms) width, height, opacity одновременно display: none / исходный display
slideUp / slideDown height, вертикальные padding и margin display: none / видим
fadeOut / fadeIn opacity display: none / видим
fadeTo(ms, 0.5) opacity до заданного значения элемент остается в потоке
toggle, slideToggle, fadeToggle как у пары выше переключает по текущей видимости

Две детали, которые в исходных пересказах часто путают:

  • hide() и show() без аргументов не анимируют ничего: элемент мгновенно получает display: none или возвращается к видимому. Анимация появляется только при переданной длительности.
  • fadeOut не просто делает элемент прозрачным: по окончании он получает display: none и перестает занимать место. Если нужно оставить место в разметке, используйте fadeTo(ms, 0).

Встроенные функции сглаживания — только "swing" (по умолчанию) и "linear". Имена вроде "easeOutBounce" работают лишь с подключенным плагином, например jQuery UI.

Свой эффект через animate

animate(свойства, длительность, easing, колбэк) плавно ведет числовые CSS-свойства к целевым значениям:

$("#box").animate({ width: 100, height: 100, opacity: 0.6 }, 800, function () {
  console.log("Квадрат готов");
});

// Относительные значения: +10px по ширине и +20px по высоте от текущих
$("#grow").on("click", function () {
  $("#box").animate({ width: "+=10", height: "+=20" }, 300);
});

Результат: блок #box за 0,8 с становится квадратом 100×100 px с прозрачностью 0,6, затем в консоли появляется Квадрат готов. Каждый клик по #grow увеличивает его на 10 px в ширину и на 20 px в высоту.

Граница метода: animate работает только с числовыми значениями. Классическая ошибка:

$("#box").animate({ backgroundColor: "#ff0000" }, 500);

Фактический результат: цвет не меняется, ошибки в консоли нет, колбэк при этом срабатывает. Исправление — либо подключить плагин цвета (jQuery Color или jQuery UI), либо отдать цвет CSS-переходу: transition: background-color .5s и смена класса через addClass. Не анимируются также transform и display.

Очередь эффектов, stop, finish и delay

Каждый эффект по умолчанию ставится в очередь fx конкретного элемента. Цепочка ниже выполнится строго по шагам, а не одновременно:

$("#box")
  .slideUp(300)
  .delay(500)
  .slideDown(300)
  .animate({ left: 200 }, 400);   // left работает при position: relative/absolute

$("#box").promise().done(function () {
  console.log("Вся очередь завершена");
});

Результат: блок сворачивается, полсекунды ждет, раскрывается, затем сдвигается вправо на 200 px, и только после этого в консоли появится строка. delay действует только на очередь эффектов — обычный код вроде css() между шагами выполнится сразу, не дожидаясь паузы.

Из-за очереди возникает самая частая ошибка на практике. Неверно:

$(".menu-item").on("mouseenter mouseleave", function () {
  $(this).find(".submenu").slideToggle(300);
});

Фактический результат: если несколько раз быстро провести мышью над пунктом, подменю продолжает открываться и закрываться еще секунды после того, как курсор ушел. Каждое событие добавило эффект в очередь. Исправление:

$(".menu-item").on("mouseenter mouseleave", function () {
  $(this).find(".submenu").stop(true, true).slideToggle(300);
});
Вызов Что делает с текущей анимацией Что делает с очередью
stop() останавливает на месте продолжает следующие
stop(true) останавливает на месте очищает
stop(true, true) переводит в конечное состояние очищает
finish() переводит в конечное состояние выполняет все до конца мгновенно

Глобальный флаг jQuery.fx.off = true отключает все анимации jQuery: эффекты сразу переходят в конечное состояние.

Нативные аналоги без jQuery

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

Задача jQuery Нативный аналог
Плавно показать/скрыть fadeIn/fadeOut класс + transition: opacity
Свернуть/развернуть блок slideToggle transition по grid-template-rows или max-height; для простых случаев <details>
Произвольная анимация из JS animate element.animate() (Web Animations API)
Остановить stop/finish animation.cancel()/animation.finish()
Дождаться конца колбэк, promise() событие transitionend, промис animation.finished

Аналог fadeToggle на CSS transitions:

.panel {
  opacity: 1;
  transition: opacity 0.4s ease;
}
.panel.is-hidden {
  opacity: 0;
  pointer-events: none;
}
document.querySelector("#toggle").addEventListener("click", () => {
  document.querySelector("#panel").classList.toggle("is-hidden");
});

В отличие от fadeOut, элемент здесь остается в потоке. Если он должен освобождать место, после события transitionend добавьте атрибут hidden.

Аналог animate на Web Animations API:

const box = document.querySelector("#box");
const anim = box.animate(
  [{ transform: "translateX(0)" }, { transform: "translateX(200px)" }],
  { duration: 400, easing: "ease-out", fill: "forwards" }
);
anim.finished.then(() => console.log("Сдвиг завершен"));

Результат: блок за 0,4 с сдвигается на 200 px вправо и остается там благодаря fill: "forwards", затем в консоли Сдвиг завершен. Анимируется transform, а не left: такой переход обычно не требует пересчета раскладки и идет плавнее.

Анимация высоты до auto на чистом CSS исторически невозможна: поэтому slide-эффекты делают через grid-template-rows: 0fr -> 1fr или ограничение max-height. Более новое interpolate-size пока поддерживается не везде.

Доступность: prefers-reduced-motion

У части пользователей в системе включено «уменьшить движение» — при вестибулярных нарушениях анимации вызывают дискомфорт. jQuery эту настройку сам не учитывает. Проверить ее можно одной строкой:

const reduce = window.matchMedia("(prefers-reduced-motion: reduce)").matches;
jQuery.fx.off = reduce;   // для legacy-кода на jQuery

Для CSS-переходов то же делается медиазапросом:

@media (prefers-reduced-motion: reduce) {
  .panel { transition: none; }
}

Состояние элемента при этом меняется: скрытый блок по-прежнему скрывается, просто без эффекта.

Когда оставить jQuery, а когда переходить

  • Проект уже на jQuery и эффекты работают — переписывать ради переписывания не нужно; достаточно добавить stop() там, где анимацию запускают события, и учесть reduced-motion.
  • Новая страница или компонент — CSS transitions для состояний, Web Animations API для последовательностей, из которых нужно управлять в JS.
  • Переход на jQuery 4 — сначала проверить код на удаленные устаревшие API (помогает плагин jQuery Migrate), и не забыть, что slim-сборка по-прежнему без эффектов.

Выводы

  • Эффекты jQuery — это модуль effects: show/hide с длительностью, slide*, fade* и animate для числовых CSS-свойств; в slim-сборке их нет.
  • Все эффекты элемента встают в очередь fx; при запуске от частых событий нужен stop(true) или stop(true, true), иначе анимации копятся.
  • animate не анимирует цвета и transform без плагинов — это задача CSS.
  • Нативный аналог: класс + CSS transition для состояний, element.animate() с промисом finished для последовательностей.
  • Учитывайте prefers-reduced-motion: в jQuery через jQuery.fx.off, в CSS — медиазапросом.

Где применяется / связь с практикой

Освойте тему на практике

С jQuery-анимацией чаще всего сталкиваются при поддержке сайтов на CMS и старых админок, а нативные transitions и Web Animations API нужны уже в любом современном интерфейсе. Чтобы уверенно работать и с тем, и с другим, нужна опора в самом языке: события, промисы, async/await, работа с DOM. Это системно разбирается на курсе JavaScript Developer. Basic. Посмотреть формат занятий и задать вопросы преподавателям можно на открытых уроках Otus.

FAQ

Почему fadeIn не срабатывает на видимом элементе?
fadeIn и slideDown действуют только на скрытые элементы; у уже видимого ничего не изменится. Для изменения прозрачности видимого блока используйте fadeTo.

Нужен ли jQuery UI для анимации?
Для встроенных эффектов — нет. jQuery UI или отдельные плагины нужны для анимации цветов, дополнительных easing-функций и эффектов вроде bounce.

OTUS Журнал
Скидка 5% 14-20 сентября на курсы (popup)