Что происходит до и после: animation-fill-mode

animation-fill-mode решает, что видно ДО старта анимации (во время animation-delay) и что остаётся ПОСЛЕ её окончания. По умолчанию (none) элемент до и после анимации выглядит как обычно, без изменений. forwards сохраняет конечный вид навсегда, backwards показывает начальный вид уже во время задержки, both объединяет оба эффекта.

Попробуй прямо сейчас: тост появляется снизу и ОСТАЁТСЯ на экране - это работа animation-fill-mode: forwards, который держит конечное состояние (opacity:1, без сдвига) даже после того, как сама анимация технически закончилась. Поменяй forwards на none (или удали строку совсем) - через полсекунды тост СНОВА исчезнет, несмотря на то что визуально уже полностью появился, потому что без forwards браузер возвращает элемент к его обычному (невидимому) стилю.

До начала: none и backwards

Если у анимации есть задержка (animation-delay), по умолчанию (none) элемент всё это время выглядит как обычно - его собственный, неанимированный стиль. backwards меняет это: элемент СРАЗУ показывает вычисленные значения ПЕРВОГО keyframe, ещё до того, как задержка закончится и анимация реально начнётся. Какой keyframe считается "первым", зависит от animation-direction: при normal и alternate это 0%/from, а при reverse и alternate-reverse - наоборот, 100%/to.

.badge { animation-name: pulse; animation-duration: 1s; animation-delay: 2s; animation-fill-mode: backwards; } - все 2 секунды задержки элемент уже выглядит так, как задано на 0% в @keyframes pulse, без "вспышки" обычного вида.

Без backwards будет "вспышка" перед стартом:

.badge { animation-name: pulse; animation-duration: 1s; animation-delay: 2s; } - все 2 секунды задержки элемент показывает свой обычный стиль, и только потом резко переключается на вид 0% - если они заметно отличаются, это выглядит как рывок.

После окончания: none и forwards

После того как анимация доиграла (или если animation-iteration-count не infinite), по умолчанию (none) элемент возвращается к своему обычному стилю - "как будто анимации и не было". forwards сохраняет вычисленные значения ПОСЛЕДНЕГО пройденного keyframe навсегда. Неочевидный момент, подтверждённый собственной проверкой: "последний" keyframe зависит не только от направления, но и от ЧЁТНОСТИ числа повторов - с animation-direction: alternate и ЧЁТНЫМ animation-iteration-count (например 2) forwards зафиксирует состояние 0%, а НЕ 100%, потому что последний (чётный) проход шёл в обратную сторону.

Есть и более коварная ловушка: forwards бессилен, если сама анимация назначена ТОЛЬКО внутри правила :hover. Пока курсор наведён, forwards честно держит конечный вид - но как только курсор уходит, правило .el:hover перестаёт действовать, и анимация СНИМАЕТСЯ ЦЕЛИКОМ вместе со своим forwards-состоянием - элемент мгновенно прыгает к базовому стилю. Это та же по сути проблема, что уже разбиралась для transition и :hover в уроке 06: если эффект должен пережить уход курсора, саму анимацию нужно вешать на БАЗОВЫЙ селектор (управляя её запуском, например, через смену имени или добавление класса через JS), а не только на :hover.

.spinner { animation-name: appear; animation-duration: .5s; animation-fill-mode: forwards; } - конечный вид сохраняется навсегда, пока сама анимация не будет убрана из каскада.

Неправильное ожидание - что forwards переживёт снятие правила :hover:

.card:hover { animation-name: appear; animation-duration: .5s; animation-fill-mode: forwards; } - при уходе курсора .card:hover перестаёт совпадать, анимация снимается целиком, forwards ничего не спасает.

Частые ошибки новичков

ОшибкаЧто происходитКак исправить
Не указать animation-fill-mode вообще и удивляться "прыжку" обратно По умолчанию none - элемент возвращается к обычному стилю сразу после конца анимации Указать animation-fill-mode: forwards, если конечный вид должен остаться
Ожидать, что forwards сработает, если анимация назначена только на :hover При уходе курсора правило :hover перестаёт действовать, и анимация снимается целиком вместе с forwards-состоянием Вешать саму анимацию на базовый селектор, а не только на :hover (как и с transition в уроке 06)
Считать, что forwards с alternate всегда фиксирует состояние 100% С чётным animation-iteration-count последний проход идёт НАЗАД, и фиксируется состояние 0% Проверять чётность числа повторов при использовании alternate вместе с forwards
Использовать animation-delay без backwards и получать "вспышку" исходного вида Все секунды задержки элемент показывает обычный стиль, а не вид 0% из @keyframes Добавить animation-fill-mode: backwards (или both), если нужно избежать вспышки

Шпаргалка

ЗаписьЧто означает
animation-fill-mode: none; (по умолчанию)До и после анимации - обычный стиль элемента
animation-fill-mode: forwards;После окончания - сохраняется вид последнего пройденного keyframe
animation-fill-mode: backwards;Во время задержки - уже виден вид первого keyframe
animation-fill-mode: both;Объединяет backwards (до) и forwards (после)
forwards + alternate + чётное число повторовФиксируется состояние 0%, а не 100%
forwards только на :hoverНе спасает - при уходе курсора анимация снимается целиком

Коротко: отвечаем на вопросы

Как сделать так, чтобы после анимации элемент остался в конечном виде, а не возвращался к исходному?

Реальный ответ с Хабра - добавить animation-fill-mode: forwards. Это заставляет браузер сохранять вычисленные значения последнего пройденного keyframe навсегда (пока сама анимация не будет убрана из каскада), вместо того чтобы возвращать элемент к обычному, неанимированному стилю сразу после окончания.

Почему не работает animation-fill-mode: forwards - анимация доигрывает до конца, но потом всё равно возвращается назад?

Частая причина, встречающаяся в реальных вопросах разработчиков - анимация назначена ТОЛЬКО внутри правила .el:hover. Пока курсор наведён, forwards честно держит конечный вид, но как только курсор уходит, .el:hover перестаёт совпадать, и анимация снимается из каскада ЦЕЛИКОМ вместе с её forwards-состоянием - элемент мгновенно прыгает к базовому стилю. Собственная проверка подтвердила: сразу после ухода курсора число активных анимаций у элемента становится равным нулю. Решение - вешать саму анимацию на базовый селектор, а не только на :hover, точно так же, как и для transition.

Категория
Поделиться в социальных сетях

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

0 Комментарии

Отправить комментарий (0)

#buttons=(Хорошо) #days=(20)

Мы используем файлы cookie для улучшения работы сайта. Подробнее
Хорошо
×