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

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

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

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

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

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

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

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

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

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

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

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

<div id="box" class="box">
</div>
<button>TOGGLE VISIBILITY</button>

А CSS – так:

.box {
  background: goldenrod;
  width: 300px;
  height: 300px;
  margin: 30px auto;
  transition: all 2s linear;
  display: block;
}
.hidden {
  display: none;
  opacity: 0;
}

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

var box = $('#box');
$('button').on('click', function () {
  box.toggleClass('hidden');
});

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

JS Bin

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

.hidden {
  display: none;
}
.visuallyhidden {
  opacity: 0;
}

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

var box = $('#box');
$('button').on('click', function () {
  box.toggleClass('visuallyhidden');
  box.toggleClass('hidden');
});

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

JS Bin

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

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

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

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

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

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

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

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

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

var box = $('#box');
$('button').on('click', function () {
  if (box.hasClass('hidden')) {
    box.removeClass('hidden');
    setTimeout(function () {
      box.removeClass('visuallyhidden');
    }, 20);
  } else {
    box.addClass('visuallyhidden');
    box.one('transitionend', function(e) {
      box.addClass('hidden');
    });
  }
});

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

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

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

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

Практика HTML5 и CSS3 с нуля до результата!

Получите бесплатный пошаговый видеокурс по основам адаптивной верстки с полного нуля на HTML5 и CSS3

Получить

Метки:

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

Комментарии Facebook:

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

  1. obbivkamebeli.by

    Ну урок конечно интересный, но где это можно реализовать???
    Буду благодарен за совет.

  2. eurosegway.com

    obbivkamebeli.by, реализация данной фишки идеально подходит для мобильной версии сайта, к примеру

  3. Fred

    Спасибо, вроде то что нужно!
    По поводу вопроса где это можно использовать, мне это понадобилось для анимации сменяющихся блоков по клику в меню, с появляющимся блоком проблем нет, плавно уходит, но вот с пропадающем только резкое скрытие, а этот способ поможет сначала плавно скрыть уходящий блок и потом на его месте плавно открыть другой.

  4. Dem

    А если вместо display использовать overflow и с transition изменить высоту блоку до нуля?

    #inter{
    overflow: hidden;
    height: 90px;
    transition:1s;
    }

    #inter:hover {
    height: 0px;
    }

  5. Владимир

    Все банально и просто. Используем вместо toggleClass, removClass и addClass show(время в миллисекундах) и hide(время в миллисекундах) ==> получаем плавность.

  6. lufter

    ну раз на чистом css невозможно реализовать и вы уже залезли в jQuery то какой смысл с классами мудохаться, добавлять удалять если в jQ есть отличные методы fadeOut() и fadeIn()?

    • Андрей Кудлай

      Это переводная статья. Внизу указан источник статьи, где Вы можете задать автору вопрос)

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

Можно использовать следующие HTML-теги и атрибуты: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

Я не робот.

Spam Protection by WP-SpamFree