Мой ответ является расширенной версией ответа
Илья Шатохин про добавление класса .no-transition.
И он в общем то полагается на костыль, но не настолько ужасный как setTimeout.
.no-transition {
transition: none !important;
}
Затем в js пишем нечто подобное
elem.classList.add("no-transition");
var triggerLayout = elem.offsetHeight;
// действия с элементом которые произойдут мгновенно
Суть такова, что работа с DOM в браузере оптимизирована таким образом, что он "группирует" все изменения и потом применяет их одновременно. Но, если в js коде обращаться к свойстам элементов, которые триггерят лэйаут, эти группы будут "дробиться" в этом месте вызова. В итоге вот эта самая строчка "var triggerLayout = elem.offsetHeight;" вызывает триггер лэйаута и операция с элементом происходит уже так, словно к нему добавлен класс без транзишена. Точно таким же образом например анимируются элементы с display: none, которые надо показать с помощью изменения opacity. Вначале вы меняете свойство display, затем триггерите лэйаут, затем добавляете класс изменяющий опасити - у вас происходит анимация. Без триггера элемент просто моментально появится.
Таблицу css триггеров можно найти тут -
csstriggers.com
+ вот тут еще пишут про это
gent.ilcore.com/2011/03/how-not-to-trigger-layout-...
Сам по себе лэйаут нужно триггерить только тогда, когда это является лучшим способом реализации анимации, ибо это влияет на производительность. На эту тему (и многие другие вещи) вам сюда -
https://developers.google.com/web/fundamentals/per...