Анимация от display: block до display: none

Анимация от display: block до display: none

От автора: Вы, возможно, уже знаете, что переходы и анимация CSS3 позволяют анимировать специальный набор свойств CSS. Одно из тех свойств, которые нельзя анимировать – display.

Отлично было бы это сделать, но на данный момент это невозможно и, думаю, никогда не станет реальностью (например, как анимировать до “display: table”?). Но есть возможность совершить обходной маневр, и один из них я здесь и опишу.

Зачем анимировать “display”?

Анимировать свойство display требуется для решения следующей проблемы:

Нужно, чтобы элемент постепенно зрительно исчезал со страницы.

Вам нехочется, чтобы этот элемент занимал место после своего исчезновения (например, требуется, чтобы его исчезновение вызывало перезаливку).

Нужно применять для анимации CSS, а не библиотеку.

По этой причине недостаточно просто анимировать opacity до нуля, так как элемент с нулевой непрозрачностью занимает то же самое место на странице. Давайте посмотрим, как шаг за шагом решить эту проблему.

Используйте Opacity и Display

Первое, о чем вы можете подумать – воспользоваться и свойством opacity, и display. Наш HTML будет выглядеть так:

А CSS – так:

Обратите внимание на то, что display: none и opacity: 0 присвоен класс “hidden”. Если переключать класс “hidden” с помощью jQuery, получится примерно такой код:

Но если так сделать, то мы не увидим эффекта перехода (определенного в блоке описаний .box). Вместо него мы увидим это (слегка отличающееся в Firefox по сравнению с Chrome/IE10):

JS Bin

Многократно нажмите кнопку ‘togglevisibility’ и увидите, как блок безо всяких переходов будет неожиданно исчезать и появляться. Чтобы это исправить, можно попробовать отделить в CSS свойство display от opacity:

Затем можно переключить оба класса, один за другим:

Помимо того, что требуется реверсировать эти две строки при появлении блока, это еще и не сработает, как видно здесь:

JS Bin

Нам нужно, чтобы элемент визуально исчезал, а затем удалялся со страницы по окончанию исчезновения идентично функции обратного вызова. (Кроме того, даже если мы скомбинируем opacity: 0 с visibility: hidden, то анимация получится хорошо, но элемент после своего исчезновения продолжит занимать место на странице, так что все это не сработает.)

Почему не работает?

До перехода к своему методу я просто объясню, почему невозможно ничего сделать, просто изменяя классы один за другим. Во-первых, если вы добавляете классы как в вышеприведенных примерах, и если переход даже сработал, то вам придется установить отдельный раздел для удаления классов и реверсирования (т.е. если блок сначала скрыт, вам придется установить его на display: block, а затем сменить непрозрачность).

Но это несущественно, потому что все равно не работает. JavaScript выполняет одну строку за другой, но не ждет, пока закончат выполняться все связанные с ней процессы, а переходит к выполнению следующей строки. (Другими словами, если в строке 1 вы выполняете анимацию или другое несинхронное событие, строка 2 будет исполняться, даже если анимация не выполнена).

Это происходит от того, что непрозрачность ‘opacity’ пытается анимироваться сразу же, и даже если на долю миллисекунды она действительно анимируется, вы этого не увидите, потому что display: none начнет действовать столь же быстро.
Можно резюмировать проблему, которую нам нужно решить, следующим образом:

Когда элемент виден, сначала анимируйте непрозрачность, а затем, когда это выполнено, сделайте его display: none.

Когда элемент невидим, сначала сделайте его display: block, затем (пока он еще визуально скрыт, но уже существует на странице), анимируйте непрозрачность.

Возможное решение

Вероятно, существуют другие способы это сделать, и я буду рад узнать, как вы бы решили эту проблему. Но вот мое мнение.
CSS тот же самый (с двумя все еще разделенными классами ‘hidden’), но jQuery будет выглядеть так:

А это он в действии:

JS Bin

Вот краткое изложение действий кода, когда блок видимый:

Добавьте класс visuallyhidden, который анимирует его до его исчезновения.

Одновременно с добавлением класса с помощью метода jQuery.one() добавляется один обработчик события, ожидающий события transitionend.

Событие transitionend запускается, когда непрозрачность анимирована, и когда это происходит, элемент устанавливается на display: block. Так как мы не можем отслеживать событие transitionend свойства display, то в ситуации, когда блок невидим, придется применить другой метод:

Сначала удаляем класс hidden, делая его display: block, пока блок визуально еще скрыт.

За это время скрипт выполнил задержку с помощью setTimeout(), после чего непрозрачность начинает анимироваться.

Примите во внимание, что некоторые браузеры требуют префикса для transitionend. Modernizr.prefixed() поможет вам в этом. Задержка очень маленькая (20 миллисекунд), но так как display: block происходит мгновенно, нам вообще не требуется большой задержки, лишь достаточной для того, чтобы позволить элементу полностью занять свое место на странице перед анимацией непрозрачности. (Замечание: внутри JSBinвChrome’е я смог применить задержку всего в одну сотую миллисекунды (0,1). Но в Firefox’е и IE10 потребовалось минимум 20мс. Может быть, это касается только JSBin, я на самом деле не знаю.)

А как бы сделали вы?

Как уже говорилось, возможно, существуют другие способы это сделать, или есть возможность внести улучшения в мой код.
Лично я считаю применение setTimeout неудовлетворительным и неизящным решением. Но ура! — оно работает, и я не считаю его способным вызывать какие-то проблемы, если только вы не собираетесь сделать на странице тонну одинаковой анимации. Но, в любом случае ,это уже другой вопрос.

На StackOverflow имеются несколько возможных решений этой проблемы, но я нахожу, что их большая часть, если не все, на самом деле не решают ее.

Автор: Louis Lazaris

Источник: //www.impressivewebs.com/

Редакция: Команда webformyself.

Метки:

Похожие статьи:

Комментарии Вконтакте:

Комментарии (8)