[Из песочницы] Все об SVG анимации
В данной статье я хочу осветить тонкости работы с SVG-графикой, SVG анимация (в том числе и path), проблемы и способы их решения, а также разнообразные подводные камни, коих в SVG огромное множество. Эту статью я позиционирую как подробное руководство.
Здесь не будет никаких плагинов, библиотек и прочего, речь пойдет только о чистом SVG.
Единственный инструмент, который я буду использовать, это Adobe Illustrator.
Предисловие
Все началось со скучной лекции и в надежде занять себя хоть чем-то, я решил изучить SVG графику, а именно анимацию. К моему удивлению в интернете было совсем мало информации. Везде дублировалась информация, объясняющая основы, а про анимацию вообще от силы 2–3 ссылки с абсолютно идентичной информацией, являющейся переводом статьи A Guide to SVG Animations (SMIL) за авторством Сары Суэйдан.
Ее статья рассказывает об о всем, но поверхностно. Тем не менее настоятельно рекомендую с ней ознакомится. *Ссылка на перевод*
Следующие несколько недель я провел, собирая информацию по кусочкам из разных источников. Результатом этих поисков является эта статья
Правильный экспорт SVG из Illustrator
Этот раздел посвящен особенностям и проблемам Adobe Illustrator, так что, если ты используешь не Illustrator, то можешь пропустить эту часть.
Подготовить документ для анимации очень важный этап, пренебрежительное отношение к которому может обернуться очень неприятными последствиями. Учить тебя как лучше рисовать в Illustrator я не стану. Единственное что я скажу — при отрисовке фигур следует следить за значениями, желательно что бы они имели лишь одно число после запятой, а лучше вообще были целыми. Следовать этому правилу не обязательно, но оно уменьшит размер файла, упростит дальнейшую анимацию и визуально сократит объем информации. Взгляни
В примере одна и та же кривая, но в первом случае одна цифра после запятой, а во втором три. Этак кривая имеет всего 4 точки, а второй пример на треть длиннее первого. Представь, как много места займет кривая из 20 точек.
После того как каркас нарисован нужно сохранить изображение как SVG файл. Для этого есть два пути — «Сохранить как» или «Экспортировать как». Но какой способ выбрать? Если доверяешь мне — лучше используй «сохранить как». Если хочешь знать почему, то разворачивай спойлер.
Детально объяснять все параметры я не вижу смысла, с этим прекрасно справляется сам Illustrator в секции «Описание».
Как видно «сохранить» имеет больше настроек нежели «экспортировать» и для кого-то это уже будет весомой причиной отказаться от экспортирования, но мы продолжим.
Если открыть файлы, сохраненные обоими способами, в браузере, разницы мы не заметим. Однако в данный момент нас больше интересует не внешний вид, а начинка, поэтому сделаем тоже самое, но уже через текстовый редактор. Тут отличия станут более очевидны. Предлагаю тебе самому посмотреть и сделать выводы, я ничего в файлах не изменял просто скопировал целиком как есть.
Экспортировать
Сохранить
Помимо отличий в именовании CSS классов и оформления в целом, которые кто-то может посчитать вкусовщиной, есть и другие проблемы. При «экспортировании» все изображение уменьшилось в 2 раза. Судить об этом можно по размерам фигур и атрибуту viewBox. Так как это векторная графика хуже от этого не стало, но все равно не приятно. «Сохранение» же оставило размеры, которые я указал в Illustrator.
Но все это цветочки по сравнению с тем какую свинью может подложить «экспортирование». Конкретно в данных примерах этой проблемы нет, вероятно потому что изображение очень простое. Однако я столкнулся с ней, когда экспортировал другую мою работу. Вот ее скриншот
Объем файла достаточно большой, так что я приведу только проблемную часть
Заметил что-нибудь необычное? Если ты косо смотришь на атрибут transform, то ты прав. Именно он портит всю малину. При «экспортировании» изображения Illustrator приписывает его ко ВСЕМ элементам
Если ты до сих пор не понимаешь моего негодования, то я объясню: если захочешь анимировать перемещение такого элемента, то он будет смещаться в сторону. В данном случае на 5.5 по обеим осям. Связанно это с тем, что анимация перемещения изменяет атрибут transform сбрасывая все прошлые значения. Конечно это можно обойти, но разве не лучше избежать проблемы, чем потом исправлять ее последствия…
На данный момент мне довелось заметить только эту проблему, но это не значит, что она единственная. Если здраво оценить ситуацию окажется, что «сохранить как» выигрывает во всем. Именно поэтому я советую использовать именно его.
Способы импорта SVG документа в HTML
Перед тем как я приступлю непосредственно к анимации, я хочу рассказать про то как встроить SVG на страничку. Каждый способ имеет свои «особенности», которые оказывают прямое влияние на анимацию. И если про них не рассказать, то статья будет не полной.
Предположим, что у тебя уже есть готовый SVG с интерактивной анимацией и осталось встроить этот документ на сайт. Как же это сделать?
Вариант номер раз — вспомнить что SVG это тоже изображение и его можно импортировать стандартными средствами HTML. Можно создать тег ссылкой на документ
Или задать SVG в качестве фонового изображения
#box { background-image: url("Hello_again.svg"); }
Главный минус этого способа — изолированность изображения. SVG как экспонат в музее — смотреть можно, трогать руками нет. Анимация внутри будет работать, но ни о никакой интерактивности речи быть не может. Если же, например, анимация запускается по клику пользователя или есть необходимость динамически менять содержимое SVG документа, то этот способ не для тебя.
Вариант номер два — создать объект из SVG, использовав теги или . Так же есть возможность использовать , что создать фрейм, но этот способ я использовать не рекомендуют т.к. требуется костыль для всех браузеров, что бы этот вариант отображался корректно
Тут уже дела обстоят по лучше. Анимации получают возможность быть интерактивными, но только если объявлены внутри SVG документа, а содержимое доступно для внешнего JavaScript. Еще и могут показать заглушку, если вдруг изображение не загрузится.
Вариант номер три — просто вставит содержимое SVG документа прямо во внутрь HTML. Да так можно. Поддержка SVG появилась в стандарте HTML5. Так как SVG по сути является частью самой странички, то доступ к нему есть везде. Анимации и стили элементов могут быть объявлены как внутри SVG, так и во внешних файлах. Минус заключается в том, что такие изображения просто так не кэшируются отдельно от страницы
...
SVG анимация
Есть два основных способа анимации SVG элемента:
- CSS анимация
- SMIL анимация, встроенная в SVG (на самом деле это SVG анимация, которая базируется на SMIL и расширяет его функционал)
Лично я разделяю их как анимацию «внешнюю» и «внутреннюю». Данное деление условно, но все же они имеют функциональные различия. Если говорить об отличиях в общем: CSS — имеет лучшую поддержку браузерами; SMIL — обладает большим функционалом. Трудно сказать, что использовать лучше т.к. они во многом похожи. Выбор завит от поставленной задачи, поэтому я просто скажу основные причины, использовать SMIL вместо CSS
SMIL — когда нужно:
- Сделать то что не смог CSS (анимировать не поддерживаемый атрибут и т.д.)
- Иметь более точный контроль над анимацией
- Сделать морфинг контура (анимация атрибута d у тега path)
- Синхронизировать анимации
- Сделать интерактивные анимации
Если я написал, что SMIL нужно использовать для интерактивных анимаций, то это не значит, что того же нельзя сделать с помощью CSS. Просто SMIL является более функциональным и сложным инструментом. И именно поэтому его следует использовать только при необходимости. Если анимация простая и можно обойтись CSS, то так и следует сделать.
Анимация средствами CSS
Тут ничего нового. Любой SVG элемент мы можем анимировать так же, как мы это делаем с HTML. Все анимации создаются с помощью @keyframes. Так как CSS-анимация это уже другая тема, я подробно останавливаться на этом пункте не буду, в сети полно документации и руководств на эту тему. Все что там описывается применимо и к SVG, а я лишь приведу несколько примеров.
SVG документ имеет внутренние таблицы стилей, вот в них мы и будем писать анимацию
Анимировать SVG атрибут так же просто, как и CSS атрибуты
@keyframes reduce_radius {
from { r: 10; }
to { r: 3; }
}
@keyframes change_fill {
0% { fill: #49549E; }
75% { fill: #1bceb1; }
100% { fill: #1bce4f; }
}
Можно задавать значения как в процентах, так и конструкцией from-to
За тем остается просто применить созданные анимации к нужному элементу
.circle { animation: change_fill 1s, popup 2s; }
Все что я описывал выше — это статичные анимации, интерактивностью там и не пахнет. А что делать если уже очень хочется? Ну кое-что все-таки можно сделать интерактивным и на CSS. Например, если использовать transition в сочетании с псевдоклассом hover
.circle { fill: #49549E; transition: .3s; }
.circle:hover { fill: #1bceb1; }
При наведении на элемент, он изменит свой цвет с синего на голубой за 300ms
Анимация атрибутов и небольшой кусочек интерактивности — на этом особенности CSS-анимации заканчиваются. Но этого функционала предостаточно, ведь большинство задач сводятся к анимации какого-либо атрибута. Практически любой SVG атрибут можно анимировать. И когда я пишу практически любой я имею ввиду, что если ты выберешь случайный атрибут и он окажется не анимируемым, то тебе ОЧЕНЬ повезло.
SMIL анимация
Сразу стоит сказать, что SMIL анимация стара как мир и она потихоньку вымирает, поддержка браузеров пусть и приличная, но все же меньше чем у CSS Animation, однако есть причина, почему SMIL все еще привлекателен — он может то, что не может CSS.
Про SMIL я буду рассказывать подробнее, потому что тут есть множество подводных камней, про которые редко где пишут. Да и тема эта менее популярная чем CSS. Основные теги для анимации это
Начнем с тяжёлой артиллерии.
Как применить анимацию к элементу?
Указать элемент, к которому будет применена анимация можно двумя способами
- Положить тег во внутрь элемента. Этот способ позволяет инкапсулировать анимацию внутри объекта, что облегчает чтение кода
В данном случае анимация будет применена к элементу circle - Передать ссылку на элемент. Пригодиться если хочется, что бы все анимации были собраны в одно месте
Здесь используется атрибут xlink: href в котором мы указываем id элемента к которому должна примениться анимация. Для того что бы этот способ работал необходимо определить пространство имен xlink. Это делается в теге
С SVG 2 атрибут xlink: href устарел, вместо него рекомендуется использовать href, который не требуется определять пространство имен xlink
...
Для тех, кто заметил сходство с CSS селекторами спешу огорчить: обратиться к элементам по классу не получится
Это не работает!
Как указать атрибут для анимации?
Для этого существует attributeName. В качестве значения выступает имя атрибута, которое мы будем анимировать.
Указав в attributeName значение r мы сообщаем, что собираемся анимировать радиус окружности
Что такое attributeType и почему он тебе не нужен?
Потому что он бесполезный
В теории может возникнуть такой момент, когда имена атрибутов в CSS и XML будут совпадать, что может привести к проблемам. И что бы разрешить этот конфликт нужно явно указать пространство имен. Есть два стула способа: указать префикс или использовать attributeType. Начнем с префикса.
Везде пишут примерно следующее:
Можно указать XMLNS префикс для атрибута, чтобы явно указать его пространство имен
Этот способ упоминается вскользь и без примеров. Вот и я не буду изменять традициям. (советую тебе тут остановиться, забыть про префиксы как про страшный сон и переходить к attributeType, я тебя предупредил)
Для начала нужно найти более точное определение, а, как известно, самые точные определения в спецификациях и в стандартах.
Перевод определения гласит примерно следующее:«Определяет имя целевого атрибута. Префикс XMLNS может использоваться для указания пространства имен XML для атрибута. Префикс будет интерпретироваться в области действия элемента анимации.»Хмм, легче не стало. Что придет в голову человеку, который не знает XML, после прочтения такого определения? Правильно. Тоже самое что и мне.
Я понял его буквально и подумал, что это должно выглядеть так
Подумал и благополучно забыл про этот способ до написания этой статьи. Проблемы начались, когда я решил проверить его на практике. Думаю, я никого не удивлю если скажу, что это не работает. Спустя несколько часов безуспешных поисков я загуглил «xmlns prefix» и к моему удивлению увидел, что xmlns это не сам префикс, а (сконцентрируйся сейчас будет сложно) конструкция определения пространства имен с префиксами.
Выглядит она следующем образом:
<*тег* xmlns:*префикс*="*полный url адрес*" ...>
Тут я понял, что ничего не понял…в самом начале…и сейчас в принципе тожеСпустя еще пару часов я наконец нашел, что искал в Namespaces in XML. Вот оригинальный пример:
Но знаешь, что самое смешное? Это все равно не работает. Хотя сделано все по книжке
Ошибок нет и не должно быть, потому что все сделано по правилам, но проблема в том, что мы получим круг с без радиуса. Такой же результат будет если просто не писать атрибут r.
Эпилог: SVG игнорирует атрибуты с префиксом. В итоге даже если SMIL действительно анимирует атрибут с префиксом, результата этой анимации ты не увидишь.
В свое оправдание скажу, что разбирался только с SVG, а именно с его анимацией, поэтому гуру XML порошу отложить факелы и вилы в сторону. Если знаете, как заставить этот способ работать, милости прошу в комментарии
Что бы явно указать к чему принадлежит анимируемый атрибут используется attributeType. Он принимает 3 значения CSS, XML, auto. Если явно не указывать attributeType, то будет использоваться auto. В этом случае сначала проверяются CSS свойства и если нет совпадений, то проверяются атрибуты целевого элемента. В примере укажем, что собираемся анимировать именно CSS свойство
Отлично, attributeType позволяет легко и без костылей указать к чему относится анимируемый атрибут, тем самым решая «проблему», которой даже не существует.
Неожиданно, правда? Как я сказал в начале главы — SMIL вымирает и связанно это с тем, что анимацию переводят на рельсы CSS. Большинство дублирующийся атрибутов абсолютно идентичны друг другу, т.е. не важно принадлежит атрибут CSS или SMIL результат будет один и тот же. А в сочетании со значением auto по умолчанию, необходимость в явном определении attributeType отпадает.
Минутка интересных фактов: атрибут attributeType не поддерживается SVG. Откуда тогда он взялся? Он пришел к нам из SMIL Animation, на котором базируется SVG анимация. А еще attributeType удален после SVG 1.1 Second Edition. Все пруфы тут
Как определить значения анимации?
Указать атрибут для анимации недостаточно, необходимо определить его значения. Тут на сцену выходят from, to, by, values.
Начнем с парочки, которая всегда вместе from и to. Смысл их существования очевиден, from указывает на начало, to на конец
Результатом выполнения анимации будет плавное изменение радиуса окружности с 10 до 45
Пусть я и сказал, что они всегда вместе, to так же может использоваться и без явного объявления from. В таком случае from примет значение, определенное в целевом элементе. Для примера выше анимация будет начинаться с 25.
Если есть необходимость указать набор из нескольких значений используется values. Значения перечисляются через точку с запятой
Значение радиуса уменьшится до 15, после увеличится до 50 и затем вернется в начальное положение
Последний на очереди by. Ему не важно «откуда» и «куда», все что его интересует это «на сколько». Иначе говоря, вместо абсолютных значений он работает с относительными
Как итог анимации — радиус увеличится на 15, то есть получится 25+15=40
Так же по просторам руководств ходит легенда, что »by может использоваться для указания величины, на которую анимация должна продвинутся». Я понимаю это так: если from=20, to=50, и задан by=10, то этот путь должен преодолеваться «прыжками» по 10, т.е. 20, 30, 40, 50. Но как бы я не пытался, что с by, что без него, анимация ни капли не изменялась. Так же я не нашел подтверждения в спецификации. Похоже это просто ошибка.
Наибольшим приоритетом обладает values, затем идет from-to, последний by. Наименьший приоритет by объясняет почему «легенда» не может работать в принципе. Однако by работает в связке с from, в этом варианте from просто переопределяет текущее положение элемента
Тут анимация вместо 50 начнется с 70 и закончится на 100
Еще про относительные анимации
Можно заставить остальные атрибуты работать так же, как и by. Делается это с помощью атрибута additive, который имеет два положения — replace и sum. Первый стоит по умолчанию, поэтому нас интересует второй. При значении sum все атрибуты будут прибавляться к текущему значению целевого элемента, т.е. при анимации радиуса равного 20, со значениями form=5 и to=15, то анимация будет с 20+5 до 20+15
При выполнении анимации произойдет резкий скачек в положение 25, что не есть хорошо (если, конечно, так не задумано). Этого можно избежать при form=0, но тогда теряется смысл использования sum потому что тот же эффект можно получить и без additive используя by
Как по мне второй способ гораздо понятнее и удобнее
Где указывать длительность анимации?
Остался последний обязательный атрибут чтобы сделать рабочую анимацию — и это dur. Значение атрибута определяет длительность анимации, которое можно указывать как в секундах, так и в миллисекундах
По последней строчке, можно догадаться что есть еще кое-что…
Так же можно указывать значения в минутах и даже часах
Хрен его знает, на кой ляд тебе сдалось указывать значения в часах, но я в чужие дела не лезу, хочешь, значит есть за чем…
Для других атрибутов временные значения задаются в таких же формах
Что сделать, что бы анимация не возвращалась в начало?
Атрибут fill (не путайте этот атрибут с его тезкой) отвечает за поведение элемента после окончания анимации. Предусмотрено две опции:
- remove (значение по умолчанию) — как только анимация достигает своего конца, все преобразования сбрасываются и элемент принимает состояние как до анимации
- freeze — элемент застывает в конечном положении анимации
Можно ли зациклить анимацию?
Ответ — да. Для этого в атрибуте repeatCount указывается значение indefinite. Атрибут определяет число повторений анимации и по умолчанию имеет 1, но можно указать любое число
Первая будет повторяться бесконечно, вторая отработает 3 раза
Теперь меня бесят бесконечные анимации, ее можно выключить через время?
Для таких раздражительных людей сделали repeatDur. Этот атрибут останавливает воспроизведение анимации, через определенное времени с начала воспроизведения анимации! Проще говоря repeatDur ограничивает время длительности анимации. Главное отличие от repeatCount в том, что анимация может быть остановлена в середине
Анимация прервется в середине второй итерации
А что если я хочу, чтобы анимация начиналась не сразу?
Тогда для тебя, мой друг, предусмотрен атрибут begin. Отвечает он за то, когда начнется анимация. Этот атрибут очень полезен, потому что так же используется для синхронизации нескольких анимаций, но об этом чуть позже.
Если нужно указать обычную задержку запуска, то пишем через какой промежуток времени должна начаться анимация после открытия документа
Воспроизведение начнётся через 1,5 секунды
Так же можно указать отрицательное значение. Тогда анимация начнется не с начала, а в том месте где она была бы через указанный промежуток времени
Анимация начнется с открытием документа, но будет воспроизводиться с середины
Делаем анимации интерактивными
В качестве значения begin можно указать событие, при котором начнется анимация, но без приставки «on». Например, если хочется сделать анимацию по клику, то вместо «onclick» пишем click
В примере выше анимация начнется при клике на элемент, к которому применена анимация. Если необходимо запустить анимацию по событию с другого элемента, то нужно указать его id
...
Еще можно указать несколько условий начала анимации. Для этого нужно перечислять их через точку с запятой
Анимация начнется при загрузке документа и по клику
Поддерживаются далеко не все события, но работают большинство событий, связанных с мышью. Я не стану перечислять их все, доступные события можно найти где то тут. Так же никто не отменял метод научного тыка.
Анимация перезапускается, не достигнув конца, как это починить?
Я приведу простой пример. Здесь анимация начинается по клику. Если пользователь так и не нажмет, то предусмотрен автоматический запуск через 3 секунды
Но появляется проблема: если пользователь нажмет до автоматического таймера то, когда пройдет 3 секунды анимация перезапустится, так и не дойдя до конца. На помощь придет атрибут restart в значении whenNotActive. Всего у него их три
- always стоит по умолчанию — разрешает перезапускать анимацию в любой момент времени
- whenNotActive — анимация может быть запушена, если она уже не воспроизводится
- never — запрещает перезапуск анимации
Проблема решена, хотя в большинстве случаев можно обойтись без этого атрибута просто грамотно строя зависимости
Синхронизация анимаций
Помимо стандартных событий, по типу клика, есть события начала, конца, повторения анимации. Для того чтобы привязать событие необходимо указать id анимации и через точку begin, end, repeat соответственно
Если с первыми двумя все понятно, то с repeat все не так очевидно. В скобках пишется номер повторения, после которого нужно запустить анимацию (это число не может быть последим повторением)
Анимация запустится после двух повторений, а не каждые 2 повторения
Еще можно указывать задержку относительно события. Например, если я хочу проиграть анимацию через 2 секунды после начала другой
Или запустить анимацию за секунду, до окончания другой
На что еще способен begin…
хотел я назвать этот раздел, но правильнее его назвать «Что он должен уметь, но не умеет?». По уже моей любимой спецификации у begin должно быть еще два значения, которые он должен принимать. Первый это accessKey, который запускает анимацию по нажатию клавиши, указанной в формате Unicode. Второй wallclock, определяющий начало анимации по реальному времени. И там можно указать не только часы, но даже месяц и год, в общем полный набор.
К сожалению, ни один из них не захотел работать. Хотя не велика потеря, ведь необходимость в них все равно сомнительная
Не знаю в чем проблема, может их не поддерживает мой браузер, а может что-то еще…
Могу ли я прервать анимацию?
Это можно сделать атрибутом end. По своему использованию он идентичен begin, так же можно указывать время, события, и т.д. Как можно заметить это уже не первый (и не последний) способ прерывать анимацию, ведь есть repeatDur где тоже можно фиксировать длительность анимации. И пусть в end тоже можно указывать время напрямую, его отличительными особенностями являются привязка к событиям и возможность указать список значений.
Предположим, что у нас есть элемент, у которого есть состояние покоя и активности. Второе активируется при клике. И мы хотим прервать анимацию покоя с началом активности. Реализовать подобную задумку можно так
Анимация покоя запущена по умолчанию. При клике на элемент запустится анимация активности и прервет анимацию покоя
Комбинирование атрибутов end и begin
Как уже известно и begin, и end могут принимать список значений, но все еще не понятно, как будет вести себя анимация если указать список в обоих атрибутах. А получится, своего рода, повторения с настраиваемой длительностью и интервалами между ними… не понятно? Сейчас все объясню.
Первое, что нужно знать — количество значений в списках должно совпадать. Каждая пара значений begin-end определяет одно «повторение». А время между концом одного «повторения» и началом следующего определяет задержку. Я неспроста называю их «повторениями», анимация не приостанавливается и продолжатся, а прерывается и начинается с начала. Выходит, мы можем отдельно регулировать длительность каждого повторения и устанавливать разные задержки после каждого повторения
В примере анимация имеет 3 «повторения». Первый начнется через секунду после загрузки документа и продлится лишь одну секунду из трех. За тем задержка в 3 секунды, и после нее полная анимация в 3 секунды. Опять задержка, но уже в 1 секунду. Последнее повторение прервется после двух секунд анимации
А можно еще как-нибудь прервать анимацию?
Еще парочка бесполезных атрибутов в копилку
Конееееечно, есть еще целых два атрибута — min и max. Как понятно из названия min определяет минимальную, а max максимальную длительность. Сначала длительность анимации рассчитывается по значениям dur, repeatCount, repeatDur, end. А после полученная длительность подгоняется под рамки, задаваемые min и max. На бумаге все красиво, посмотрим, как это работает на практике.
С max все просто, это еще один атрибут задающий верхнюю границу. Если вычисленная длительность меньше max, то он игнорируется, а если больше, то длительность анимации становится равна max
Прервется на 4 секунде
А вот min, повезло меньше. Если вычисленная длительность анимации больше чем min, то он игнорируется, что логично. Однако если вычисленная длительность меньше чем min, то он… иногда игнорируется, а иногда нет.
Чего, почему?! Вот в этом моменте очень легко запутаться, так что читай внимательно.
У нас есть два варианта, когда вычисленная длительность меньше min:
- Потому что сама анимация закончилась, т.е. dur * repeatCount < min
В этом варианте атрибут min просто игнорируется, анимация остановится на четвертой секунде - Потому что repeatDur или end ограничил длительность. Тут происходит еще одно ветвление
Из-за обилия атрибутов, прерывающих анимацию, возникает сильная путаница. По итогу большого смысла в max и min нет, ведь грамотно написанная анимация исключает необходимость в их.
Как управлять ключевыми кадрам и где указывать функцию времени?
Для этого нужно знать атрибуты keyTimes, keySplines, calcMode. Указав в values список, мы объявляем ключевые кадры, но они распределены равномерно. Благодаря атрибуту keyTimes мы можем ускорять или замедлять переход из одного состояния в другое. В нем, так же в виде списка, указываются значения для каждого кадра. Значения представляют положение ключевого кадра на временной оси в процентном соотношении, относительно длительности всей анимации (0 — 0%; 0,5 — 50%; 1 — 100%).
Есть несколько правил: каждое значение представляет число с плавающей точкой от 0 до 1, кол-во значений в списках должно совпадать, первое значение обязательно 0, а последнее 1, каждое следующее значение должно быть больше предыдущего. Думаю, ты понимаешь, что нет смысла использовать keyTimes без values. А теперь пример
По умолчанию все преобразования происходят линейно, чтобы это изменить нужно указать другой режим в calcMode. И вариантов тут не много:
- linear — стандартное значение, в объяснении не нуждается
- paced — временные промежутки рассчитываются так, что бы скорость между ключевыми кадрами была постоянной
- discrete — анимация переключается между ключевыми кадрами скачками, без интерполяции
- spline — можно сказать, что это ручной режим управления (о нем по позже)
К сожалению, это все встроенные функции, тут ты не найдешь ease in\out как в CSS. Так что&n