Костыль с useMount и setTimeout тут лишний, CSSTransition и так из коробки может делать mountOnEnter и unmountOnExit - этого достаточно. Лишний useState на animationIn, достаточно сделать просто in={opened}. Лишний CSSTransition, достаточно одного над container'ом, а разные анимации для content и overlay делаются в CSS - .transition-enter .overlay { ... }, .transition-enter .content { ... } и т.д. _Каскадные_ таблицы стилей, ага. В общем, перед тем как кого-то пытаться учить, надо бы сначала самому разобраться и подготовить качественный материал, что бы не учить плохому.
Если бы еще пример подготовили, который можно потестировать, было бы вообще замечательно! а то на словах все герои, а как сделать, что то нужно, все перестают отвечать :)
Спасибо за видео! Было бы круто разобрать анимацию перехода между двумя страницами, когда например из какого-то небольшого блока появляется вся страница, обычно так делают в мобильных приложениях. Конечно, чтобы все было синхронизировано с роутером.
@@АлександрОкатьев-р4с да это вообще ни разу не просто. Допустим у вас есть компонент на странице, который является шапкой на другой странице. Вы на него кликаете и он разворачивается в полноценную страницу. Как это все анимировать и связать с роутером (чтоб можно было нажать назад хотяб), будет ли это тот же самый компонент в итоге, а если нет, то в какой момент подменять один на другой, в общем нюансов очень много, это не тривиальная задача. Ведь цель не забить гвоздями, а сделать какое универсальное решение.
В этом подходе есть нюанс, тебе всегда придётся держать нужный диалог в разметке, а если их больше одного, то получаеться жирная разметка. Хорошо бы увидеть пример, при возможности не привязываться к разметке ( вызов с хука, когда нужно подтверждение операции - то есть при клике открывается диалог, если он вернулся с положительным эффектом, то продолжить чейнинг на удаление ). Пример из видео интересен для отображения, но не для взаимодействия, в то же время, интересно увидеть кастомные диалог, все таки любу подключать - это одно, а вот как это работает под капотом - интереснее для понимание, зная это, можно набросать свою анимацию и не только к диалогам.
Чаще всего я Confirm диалоги вставляю в разметку возле кнопки, которая их вызывает. Т.е. делаю "жирную разметку". Это достаточно просто поддерживать, хоть и больше JSX кода
Daamn... Все было так просто... Я, как посмотрел ролик про порталы, сразу радостно побежал прикручивать туда react transition group с тем же setTimeout. Уже не помню, что у меня там не получилось, но стал ждать этот ролик) Спасибо за подробное объяснение, хоть кейс и не особо сложный, иногда можно затупить и в таком случае)))
Лайк !!! Единственное что я изменил бы, так это вместо react-transition-group использовал компонент Phased из библиотеки reCONDITION. Компонент в 50 строчек позволяет отслеживать жизненный цикл и передает в качестве пропа фазы рендеринга. Следовательно получаем тот же самый transition только весом в 200 раз меньше)
Спасибо за видео :) Вместо setTimeout есть вариант использовать onAnimatinoEnd. Но событие onAnimatinoEnd срабатывает так, что модалка успеет вернуться в исходное состояние. Так что надо в анимации заюзать animation-fill-mode: forwards
Спасибо большое, прикольно, что думаешь касательно использования паттерна месседжинг через кастомные ивенты и класса Modal Controller как source of truth. Потом просто передавая управление модальным окном через useImperativeHandler, который является интерфейсом для методов, которые диспатчат кастомные ивенты, что и приводит через несколько слоев абстракции ко всем изменениям. Как-по мне, с точки зрение универсальности и расширяемости, это лучший вариант (еще раз, это не какого-либо рода критика, а вопрос)
@@it-sin9kчерез children, все как у вас, только реализовано через шаблоны контроллер и меседжинг для уменьшения зависимостей, увеличения расширяемости и избежания ререндеров (стейт не меняется)
Сталкивался с таким кейсом при работе с модальным окном, когда контент внутри этого модального окна - динамический. И при закрытии окна надо было что то сделать с этим контентом. А так как есть анимация закрытия (т.е. мы будем видеть содержимое, пока длится анимация), то видно, как контет меняется внутри окна. Лечилось добавлением метода doАfterСlosе, который вызвался если и окно закрыто и анимация завершилась.
@@it-sin9k КОДСЭНДБОКС/s/epic-pare-30g9ry Там надо ещё дополнительно флаг appear проставлять, мб про него забыл А ещё там не всегда обязательно прокидывать рефы)
Да, Я тоже так делала, и кстати без рефов и просто использовала Transition компонент. Не поняла зачем был timeout, так при использовании CSS Transition group и соответствующих пропсов все итак сработает и при открытии и закрытии. Жаль, что не увидела видео когда сама делала, никак что-то со стилями, точнее с их переназванием не получалось😅
Проблема с абстрактным именем Layout в том, что если у тебя он будет не один а десяток, то это усложняет поддержку и приводит к ошибкам импортов, так как приходится внимательнее смотреть что ты импортируешь, а так же если делать переход в Idea в файл кликом по компоненту, тебе будет предложено перейти в кучу всех этих layout и не понятно куда именно, вообщем как по мне имена компонентов должны быть либо уникальные либо все таки говорить где они используются
Глобальная константа кмк зло. Т.к. нельзя кастомизировать отдельный попап. Все конечно зависит от задачи, но значение можно передавать в хук useMounted из самого компонента
Спасибо за ссылку на гитхаб) уже скопипастил себе в UI kit, и зарефакторил на ts) скоро переделаю на css in js (emotion), если кому надо - пишите, могу залить в отдельный репо)
@@it-sin9k Очень круто) Можно будет менять длительность анимации в одной константе) А вообще, делаю это в качестве развлечения) В реальной работе, я бы воспользовался готовым и протестированным npm пакетом)
Приветствую, а куда исчезли уроки по трюкам реакт-роутера для попап окон? На медеуме есть статья, но ссылки на видео - приватные. Очень бы хотелось увидеть ваш подход.Заранее благодарю и снимаю шляпу перед автором.
@@it-sin9k Устарели, я делал по вашей статье, роутер начал ругаться, что нельзя так делать. Плиз - перезапустите, по модальным окнам, чтобы контент отображалеся в урле - огонь!
Оффтоп, но про модалки: antd, модалка написана так, что она всегда в доме, просто не видна, и вроде бы на это есть свои причины ("так правильнее", но я хз почему) Кейс - компонент, в котором в том числе есть модалка, может сильно менять свой внешний вид и состояние модалки по бизнес-логике должно сбрасываться, но этого естессна не происходит. Приходится костылять и обнулять все useState вручную. Проклацали модалку, закрыли её без сохранения, компонент изменил внешний вид (там чет типа таба), но модалка всё ещё с тем же стейтом - приходится обнулять ручками. Это норма, такой подход?)
Привет, хорошее видео)Немного нубский вопрос, а нельзя было сделать просто вот так? if(opened) {setTimeout(() => return false), 300)} чтобы не делать еще одну переменную для этого?
Недавно понадобилось сделать попапы и вспомнил про это видео, неплохо так помогло. Много кода пришлось переписать конечно, но это скорее в плюс мне как начинающему разработчику - больше разобрался в теме и самой либе. Но вот столкнулся с проблемой, что при открытии попапа с клавиатуры, фокус остаётся под оверлеем. То есть сначала через таб я должен пробежаться по всем компонентам страницы, а только потом фокус попадает на модалку. Это же и на демке воспроизводится: если открыть первую модалку, а потом нажать tab -> enter, откроется вторая модалка. Есть ли какие - то не слишком костыльные варианты переместить фокус при открытии модалки на неё и как бы заблокировать в пределах разметки с контентом?
Погуглите такой термин Focus Trap. Это как раз то что вам нужно) я его в видео решил не добавлять, думал отдельное видео сделать, но так и не добрался)
о а я писал фабрику контейнеров для виджетов, как модалку, примерное апи (для ui рендера использовал solidjs, но можно и реакт): const AwesomeWidget = createViewWidget({ variant: Primary(), connector: ... , // здесь можно соединить с каким-то стейт-менеджером, например я использовал effector plugins: [ClickOutside({ ignoreNodes: [Node1, Node2], events: ['touchstart,' ...] })], }) const ClickOutside = createPlugin({ creator([ element, config ]) => ({ onMount,(){...}, unMount() {...} }) // тут различная логика }) можно создавать плагины со своими анимациями, блок скролла, dnd и с помощью коннектора со стейт-менеджером могу вне ui-части дергать и смотреть открыт виджет (модалка) или нет🙃
Госпаде, ну и наворотил jsx-a) Можно немного легче сделать, вот пример) ruclips.net/video/eS0GL73tkmw/видео.html&ab_channel=ArchakovBlog на 10:20 , не реклама)
Изучил реализацию из видео. Есть только один вопрос по поводу того, что все попапы всегда отображаются на странице, но только не видны. Это может ударить сильно по перфомансу. Идея моего же попапа, что он удаляется из DOM после закрытия
Эй эй бро Гани видево про дебаг анимации Заждался уже там еще 500 тел ждут (наверно) И если есть возможность раз жуй порядок загрузки CSS JS html в самом дебаге имеется ввиду вкладка performance
Лол) и вправду это наша тема) Раскопал в просторах интернета) "С бóльшего: в Беларуси употребляется в значении 'в основном'. Заимствование из белорусского языка (з большага). На мой взгляд, оценивается как просторечие."
500 лайков за видео о дебаге анимации в хроме
500 лайков на этом видео или на комменте?
@@darkside2436 на комменте)
Может, 314 лайков хватит? )
@@vtiunov Нет) я пока другие видео сделаю))
Ждем-с
500 лайков за видео о CSSTransition
Костыль с useMount и setTimeout тут лишний, CSSTransition и так из коробки может делать mountOnEnter и unmountOnExit - этого достаточно. Лишний useState на animationIn, достаточно сделать просто in={opened}. Лишний CSSTransition, достаточно одного над container'ом, а разные анимации для content и overlay делаются в CSS - .transition-enter .overlay { ... }, .transition-enter .content { ... } и т.д. _Каскадные_ таблицы стилей, ага.
В общем, перед тем как кого-то пытаться учить, надо бы сначала самому разобраться и подготовить качественный материал, что бы не учить плохому.
Если бы еще пример подготовили, который можно потестировать, было бы вообще замечательно! а то на словах все герои, а как сделать, что то нужно, все перестают отвечать :)
@@it-sin9kкое-кто обиделся( а ещё в коде memo лишний, ведь children у нас при каждом рендере будет новый 🤫
Спасибо! Хоть в работе анимации не требуются, но кейсы полезные) Всем мирного неба над головой)
Спасибо за видео! Было бы круто разобрать анимацию перехода между двумя страницами, когда например из какого-то небольшого блока появляется вся страница, обычно так делают в мобильных приложениях. Конечно, чтобы все было синхронизировано с роутером.
Тема интересная) и браузер вроде движется в эту сторону, чтобы это стало легче, может и сделаю
да ну в целом это довольно просто, если делать в реакте, можно просто задать анимацию при маунте компонентов
хз, честно говоря так и не пробовал никогда)
@@АлександрОкатьев-р4с да это вообще ни разу не просто. Допустим у вас есть компонент на странице, который является шапкой на другой странице. Вы на него кликаете и он разворачивается в полноценную страницу. Как это все анимировать и связать с роутером (чтоб можно было нажать назад хотяб), будет ли это тот же самый компонент в итоге, а если нет, то в какой момент подменять один на другой, в общем нюансов очень много, это не тривиальная задача. Ведь цель не забить гвоздями, а сделать какое универсальное решение.
Для подобных анимаций могу порекомендовать взглянуть на пакет и подход react-flip-toolkit. Сам не пробовал но выглядит грамотно)
В этом подходе есть нюанс, тебе всегда придётся держать нужный диалог в разметке, а если их больше одного, то получаеться жирная разметка. Хорошо бы увидеть пример, при возможности не привязываться к разметке ( вызов с хука, когда нужно подтверждение операции - то есть при клике открывается диалог, если он вернулся с положительным эффектом, то продолжить чейнинг на удаление ). Пример из видео интересен для отображения, но не для взаимодействия, в то же время, интересно увидеть кастомные диалог, все таки любу подключать - это одно, а вот как это работает под капотом - интереснее для понимание, зная это, можно набросать свою анимацию и не только к диалогам.
Чаще всего я Confirm диалоги вставляю в разметку возле кнопки, которая их вызывает. Т.е. делаю "жирную разметку". Это достаточно просто поддерживать, хоть и больше JSX кода
Всегда с нетерпением жду от тебя новых видео.
Я тоже)) радуюсь каждый раз, когда видео уже опубликовано)
Daamn... Все было так просто... Я, как посмотрел ролик про порталы, сразу радостно побежал прикручивать туда react transition group с тем же setTimeout. Уже не помню, что у меня там не получилось, но стал ждать этот ролик)
Спасибо за подробное объяснение, хоть кейс и не особо сложный, иногда можно затупить и в таком случае)))
Рад, что не зря столько времени потратил на это видео))
@@it-sin9k точно не зря
Как всегда просто БОЖЕСТВЕННЫЙ УРОК! Огромное спасибо!
Лайк !!! Единственное что я изменил бы, так это вместо react-transition-group использовал компонент Phased из библиотеки reCONDITION. Компонент в 50 строчек позволяет отслеживать жизненный цикл и передает в качестве пропа фазы рендеринга. Следовательно получаем тот же самый transition только весом в 200 раз меньше)
Спасибо за видео :)
Вместо setTimeout есть вариант использовать onAnimatinoEnd. Но событие onAnimatinoEnd срабатывает так, что модалка успеет вернуться в исходное состояние. Так что надо в анимации заюзать animation-fill-mode: forwards
Спасибо большое, прикольно, что думаешь касательно использования паттерна месседжинг через кастомные ивенты и класса Modal Controller как source of truth. Потом просто передавая управление модальным окном через useImperativeHandler, который является интерфейсом для методов, которые диспатчат кастомные ивенты, что и приводит через несколько слоев абстракции ко всем изменениям. Как-по мне, с точки зрение универсальности и расширяемости, это лучший вариант (еще раз, это не какого-либо рода критика, а вопрос)
Спасибо за комментарий) а как Modal получает, какой компонент ему нужно отрисовать?
@@it-sin9kчерез children, все как у вас, только реализовано через шаблоны контроллер и меседжинг для уменьшения зависимостей, увеличения расширяемости и избежания ререндеров (стейт не меняется)
а можно пример? как интерфейс всего этого выглядит?
Извините, что не отвечал: не увидел этот комментарий. Сейчас школой занят, как со всем разберусь - загружу код @@it-sin9k
Вы сами монтажите видео? Очень круто! Особенно временная шкала понравилась.
Все сами) Все такие комментарии скриню и сбрасываю во внутренний чатик показываю Диме (человек, кто все это рисует и монтирует)
Контент - бомба, спасибо!
Инфа огонь! Спасибо.
Офигеть, чувак. Я тебя люблю
Добро пожаловать на канал!
Сталкивался с таким кейсом при работе с модальным окном, когда контент внутри этого модального окна - динамический. И при закрытии окна надо было что то сделать с этим контентом. А так как есть анимация закрытия (т.е. мы будем видеть содержимое, пока длится анимация), то видно, как контет меняется внутри окна. Лечилось добавлением метода doАfterСlosе, который вызвался если и окно закрыто и анимация завершилась.
Чтобы не костылить дополнительное состояние animationIn, можно использоват пропы appear и appearActive
Я вот с ними игрался. Чет у меня с ними не получилось :( Если демку рабочую сбросите, был бы признателен
@@it-sin9k КОДСЭНДБОКС/s/epic-pare-30g9ry
Там надо ещё дополнительно флаг appear проставлять, мб про него забыл
А ещё там не всегда обязательно прокидывать рефы)
Да, Я тоже так делала, и кстати без рефов и просто использовала Transition компонент. Не поняла зачем был timeout, так при использовании CSS Transition group и соответствующих пропсов все итак сработает и при открытии и закрытии.
Жаль, что не увидела видео когда сама делала, никак что-то со стилями, точнее с их переназванием не получалось😅
Даёшь видос про дебаггер анимаций в хроме! Спасибо за видос)
Топ контент. Спасибо!
Проблема с абстрактным именем Layout в том, что если у тебя он будет не один а десяток, то это усложняет поддержку и приводит к ошибкам импортов, так как приходится внимательнее смотреть что ты импортируешь, а так же если делать переход в Idea в файл кликом по компоненту, тебе будет предложено перейти в кучу всех этих layout и не понятно куда именно, вообщем как по мне имена компонентов должны быть либо уникальные либо все таки говорить где они используются
на мой взгляд можно было обойтись без cssTransition, но чтобы точно сказать - надо самому попробовать с ними и без них
Не я один, кажется, лайкнул оба комментария. Саша, спасибо за видео!
лайки собираются активнее, чем я думал)
@@it-sin9k пора заранее готовить видео)
@@boldureans не) пока есть в планах другое видео запилить)
Глобальная константа кмк зло. Т.к. нельзя кастомизировать отдельный попап. Все конечно зависит от задачи, но значение можно передавать в хук useMounted из самого компонента
Я уже не пытался покрыть все нюансы, реальные проекты они могут вообще тянуть константу чуть ли не из Remote Config сервисов
@@it-sin9k Я к тому что глобальные переменные зло ;)
можно вместо времени анимации в useMount использовать transitionend событие, для переключения mounted
мысль хорошая) не подумал)
А почему нет clenup и удаления timerID в useEffect, насколько я понимаю, что лучше удалять таймер? Или нет?
Спасибо за ссылку на гитхаб) уже скопипастил себе в UI kit, и зарефакторил на ts) скоро переделаю на css in js (emotion), если кому надо - пишите, могу залить в отдельный репо)
Ого) круто)
@@it-sin9k Очень круто) Можно будет менять длительность анимации в одной константе) А вообще, делаю это в качестве развлечения) В реальной работе, я бы воспользовался готовым и протестированным npm пакетом)
Приветствую, а куда исчезли уроки по трюкам реакт-роутера для попап окон? На медеуме есть статья, но ссылки на видео - приватные. Очень бы хотелось увидеть ваш подход.Заранее благодарю и снимаю шляпу перед автором.
кажется они уже устарели и задумывался о перезапуске этого плейлиста :)
@@it-sin9k Устарели, я делал по вашей статье, роутер начал ругаться, что нельзя так делать. Плиз - перезапустите, по модальным окнам, чтобы контент отображалеся в урле - огонь!
Оффтоп, но про модалки:
antd, модалка написана так, что она всегда в доме, просто не видна, и вроде бы на это есть свои причины ("так правильнее", но я хз почему)
Кейс - компонент, в котором в том числе есть модалка, может сильно менять свой внешний вид и состояние модалки по бизнес-логике должно сбрасываться, но этого естессна не происходит. Приходится костылять и обнулять все useState вручную. Проклацали модалку, закрыли её без сохранения, компонент изменил внешний вид (там чет типа таба), но модалка всё ещё с тем же стейтом - приходится обнулять ручками.
Это норма, такой подход?)
В следующем видео я как раз дам ответ на ваш вопрос) придется набраться терпения))
Синяк, не думал вместо setTimout в useEffect заюзать useTransition, или данный кейс не подходит для отслеживания отложенного состояния?
Честно говоря, я еще не знаком с этим хуком, надо потестировать как он работает :(
06:33 - а почему вместо ANIMATION_TIME не заюзать иветнлисенер с аніматіонЕнд/транзішнЕнд? Я вроде как-то так делал
Хороший комментарий, я особо им не пользовался, но видимо стоит начать) спасибо!
@@it-sin9k переделывал учебное задание, и вообще все переигралось, заюзал animationend прямо на компоненте
Привет, хорошее видео)Немного нубский вопрос, а нельзя было сделать просто вот так?
if(opened) {setTimeout(() => return false), 300)}
чтобы не делать еще одну переменную для этого?
Привет :)
React так к сожалению не работает)
Ты завернул модалку в мемо, но пропсом передаёшь функцию без useCallback, есть ли смысл в мемо?
Если передавать функцию без useCallback, то особого смысла нет. Но если кто то будет пользоваться модалкой и будет оборачивать, то это будет окупаться
По поводу костыля с animationIn: попробовал его убрать, все так же прекрасно работает
хмм, любопытно. Надо попробовать :)
Недавно понадобилось сделать попапы и вспомнил про это видео, неплохо так помогло. Много кода пришлось переписать конечно, но это скорее в плюс мне как начинающему разработчику - больше разобрался в теме и самой либе.
Но вот столкнулся с проблемой, что при открытии попапа с клавиатуры, фокус остаётся под оверлеем. То есть сначала через таб я должен пробежаться по всем компонентам страницы, а только потом фокус попадает на модалку. Это же и на демке воспроизводится: если открыть первую модалку, а потом нажать tab -> enter, откроется вторая модалка. Есть ли какие - то не слишком костыльные варианты переместить фокус при открытии модалки на неё и как бы заблокировать в пределах разметки с контентом?
Погуглите такой термин Focus Trap. Это как раз то что вам нужно) я его в видео решил не добавлять, думал отдельное видео сделать, но так и не добрался)
@@it-sin9k О, это как раз нужная мне тема. Пофиксил эту проблему и теперь модалки вообще огонь. Спасибо большое за ответ :)
о а я писал фабрику контейнеров для виджетов, как модалку, примерное апи (для ui рендера использовал solidjs, но можно и реакт):
const AwesomeWidget = createViewWidget({
variant: Primary(),
connector: ... , // здесь можно соединить с каким-то стейт-менеджером, например я использовал effector
plugins: [ClickOutside({ ignoreNodes: [Node1, Node2], events: ['touchstart,' ...] })],
})
const ClickOutside = createPlugin({
creator([ element, config ]) => ({ onMount,(){...}, unMount() {...} }) // тут различная логика
})
можно создавать плагины со своими анимациями, блок скролла, dnd
и с помощью коннектора со стейт-менеджером могу вне ui-части дергать и смотреть открыт виджет (модалка) или нет🙃
Выглядит в стиле effector, не похоже на обычный React)
Папап
Интересно как они сделали не просто дырку через children в element компонента Route, а именную
Я все подумываю записать пару видео про новый роутер)
Так, ну-ка проставили лайки на оба коммента! Да и на все что видите на канале)
Перед входом на конференцию будет расположен мобильный призывной пункт с кадыровскими собаками.
Синяк расскажи как легко выучить CSS и на чем потренироваться
Я честно говоря не знаю источников где хорошо учить. Наверное только html academy. Лучше чем просто много верстать, варианта я не видел)
не пиши opend. пиши open, setOpen
Эх как сложно джуну мне этого понять:)
Да он специально так снимает, чтобы было не понятно
Сорян) я больше делаю упор на тех кто уже имеет пару лет опыта)
@@it-sin9k для начинающих и так полон интернет. спасибо вам!
@@videoaudio7669 вы рофлите? Как раз наоборот все максимально подробно объяснено и красиво на монтаже показано
Вот почему я ничего не обещаю
Госпаде, ну и наворотил jsx-a) Можно немного легче сделать, вот пример) ruclips.net/video/eS0GL73tkmw/видео.html&ab_channel=ArchakovBlog на 10:20 , не реклама)
Такое кроме как в хэлоу ворлд нельзя делать. Посмотрел бы я на проект где все модалки в доме лежат отрендеренные и без фокус трапа
Изучил реализацию из видео. Есть только один вопрос по поводу того, что все попапы всегда отображаются на странице, но только не видны. Это может ударить сильно по перфомансу. Идея моего же попапа, что он удаляется из DOM после закрытия
@@it-sin9k Окей, понял)
@@it-sin9k а какие накладные расходы у лишних DOM деревьев, которых нет в rendering tree?
@@Xelson1337 Честно говоря, я не очень понял вопрос. Если чего то нет в рендеринге реакта, это не несет никаких расходов
Я не понял за 7 месяцев не набралось 500 лайков Вы че ах там Впадлу вниз спуститься и кликнуть 14 к просмотров Вбите 20 лайков еще зб
Эй эй бро Гани видево про дебаг анимации Заждался уже там еще 500 тел ждут (наверно) И если есть возможность раз жуй порядок загрузки CSS JS html в самом дебаге имеется ввиду вкладка performance
p.s В курсе что есть другие видео Но после твоих реально становиться понятно А не так что ну типа понял а по факту нх не понял )
Из этого видео узнал, что ты белорус. )
это да) а где в этом видео я спалился?))
@@it-sin9k 5:40 )
а что там не так?) я не понимаю)
@@it-sin9k "С большего" - только в вашей несмерживаемой ветке русского языка используется это выражение. Четкий маркер. Пока не подводил.
Лол) и вправду это наша тема) Раскопал в просторах интернета)
"С бóльшего: в Беларуси употребляется в значении 'в основном'. Заимствование из белорусского языка (з большага). На мой взгляд, оценивается как просторечие."
@it-sin9k в вашем случае анимация срабатывает только при закрытии модалки
так при открытии так же есть анимация, там же дэмка есть рабочая