Переходы на свойство отображения CSS

1450

В настоящее время я разрабатываю «мега раскрывающееся» меню CSS - в основном обычное выпадающее меню только для CSS, но содержащее различные типы контента.

На данный момент, похоже, что переходы CSS 3 не применяются к свойству display , то есть вы не можете делать какие-либо переходы из display: noneв display: block(или любую комбинацию).

Есть ли способ для меню второго уровня из приведенного выше примера «исчезать», когда кто-то наводит курсор на один из пунктов меню верхнего уровня?

Я знаю, что вы можете использовать переходы для visibility:свойства, но я не могу придумать, как использовать это эффективно.

Я также пытался использовать высоту, но это с треском провалилось.

Я также знаю, что это легко сделать с помощью JavaScript, но я хотел испытать себя на том, чтобы использовать только CSS, и я думаю, что подойду немного.

RichardTape
источник
Работает ли переход CSS, если применить его к свойству opacity, а не к отображению?
Пол Д. Уэйт
13
положение: абсолютное; видимость: скрытая; такой же, как дисплей: нет;
Джавад
8
@Jawad: Только если вы добавите что-то подобное z-index:0.
DanMan
7
@Jawad: рекомендуется никогда не использовать, visibility: hiddenесли вы не хотите, чтобы программы чтения с экрана читали его (тогда как обычные браузеры этого не делают). Он только определяет видимость элемента (как, скажем, opacity: 0), и он по-прежнему можно выбрать, щелкнуть и все, что было раньше; это просто не видно
Форест Кач
1
нет поддержки pointer-eventsв IE 8,9,10, так что это не всегда нормально
Стивен Прибилинский

Ответы:

1352

Вы можете объединить два или более переходов, и visibilityэто то, что пригодится в этот раз.

div {
  border: 1px solid #eee;
}
div > ul {
  visibility: hidden;
  opacity: 0;
  transition: visibility 0s, opacity 0.5s linear;
}
div:hover > ul {
  visibility: visible;
  opacity: 1;
}
<div>
  <ul>
    <li>Item 1</li>
    <li>Item 2</li>
    <li>Item 3</li>
  </ul>
</div>

(Не забудьте префиксы поставщика к transition собственности.)

Более подробно в этой статье .

Гильермо
источник
10
Этот ответ кажется менее трудоемким, чем другие, и дает то, что мы ожидаем от отображения: нет / блок; Спасибо. Сэкономила мне кучу времени.
Брендан
21
Да, проблема в том, что что-то позади этого будет перекрываться, даже если это не видно. Я нашел с помощью height: 0 гораздо лучшее решение
Josh Bedo
742
Это хорошо, но проблема в том, что «скрытые видимость» элементы по-прежнему занимают место, а «не отображать» - нет.
Руи Маркес
41
Я, наверное, что-то упускаю, но почему вы меняете видимость и непрозрачность? Не будет ли установка непрозрачности на 0 скрывать элемент - зачем вам нужно также установить видимость на скрытый?
GMA
21
@GeorgeMillo, если вы устанавливаете только непрозрачность, элемент фактически остается на странице рендеринга (например, вы не можете щелкнуть мышью).
Адриенденат
801

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

Я достиг эффекта, <div>установив оба s абсолютно и установив скрытый opacity: 0.

Если вы даже переключите displayсвойство с noneна block, переход на другие элементы не произойдет.

Чтобы обойти это, всегда разрешайте элементу быть display: block, но скрывайте элемент, настраивая любое из этих средств:

  1. Установите heightдля 0.
  2. Установите opacityдля 0.
  3. Расположите элемент за пределами рамки другого элемента, который имеет overflow: hidden.

Вероятно, есть и другие решения, но вы не можете выполнить переход, если переключите элемент на display: none. Например, вы можете попробовать что-то вроде этого:

div {
    display: none;
    transition: opacity 1s ease-out;
    opacity: 0;
}
div.active {
    opacity: 1;
    display: block;
}

Но это не будет сработает. Исходя из моего опыта, я обнаружил, что это ничего не делает.

Из-за этого вам всегда нужно сохранять элемент display: block- но вы можете обойти его, выполнив что-то вроде этого:

div {
    transition: opacity 1s ease-out;
    opacity: 0;
    height: 0;
    overflow: hidden;
}
div.active {
    opacity: 1;
    height: auto;
}
Джим Джефферс
источник
29
Спасибо Джиму за подробный ответ. Вы абсолютно правы в том, что если свойство display: вообще изменится, то ВСЕ ваши переходы не будут работать. Который является позором - интересно, в чем причина этого. На боковой ноте, по той же ссылке, которую я разместил в исходном вопросе, вы можете увидеть, где я нахожусь с ним. Единственная (маленькая) проблема, с которой я столкнулся, - это Chrome [5.0.375.125], когда страница загружается, вы можете увидеть, как быстро исчезает меню, когда элементы загружаются на страницу. Firefox 4.0b2 и Safari 5.0 абсолютно в порядке ... ошибка или что-то я пропустил?
RichardTape
7
Я согласен, что это правильно и будет способствовать этому; головы для будущих путешественников. Я нашел рабочее решение в Chrome, но обнаружил, что оно не работает на iPhone 4. visibility:hidden; opacity:0; -webkit-transition: all .2s ease-in-out;Мало того, что это не правильно, но целевой элемент никогда не будет отображаться. QA подведет тебя, меня и твою маму.
SimplGy
1
Вы также можете на самом деле
перенести
2
Если вы установили свое скрытое состояние height: 0;и не изменили его, переход не будет работать. Я пытался это просто пытаться перейти непрозрачность. Я должен был удалитьheight: 0;
chovy
10
Вы только что выиграли голосование overflow: hiddenза большое спасибо!
Тиаго
279

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

Пример кода (вы можете применить его к своему меню соответственно) Демо :

Добавьте следующий CSS в вашу таблицу стилей:

@-webkit-keyframes fadeIn {
    from { opacity: 0; }
      to { opacity: 1; }
}
@keyframes fadeIn {
    from { opacity: 0; }
      to { opacity: 1; }
}

Затем примените fadeInанимацию к ребенку при наведении на родительский элемент (и, конечно, установите display: block):

.parent:hover .child {
    display: block;
    -webkit-animation: fadeIn 1s;
    animation: fadeIn 1s;
}

Обновление 2019 - метод, который также поддерживает затухание:

(Требуется некоторый код JavaScript)

// We need to keep track of faded in elements so we can apply fade out later in CSS
document.addEventListener('animationstart', function (e) {
  if (e.animationName === 'fade-in') {
      e.target.classList.add('did-fade-in');
  }
});

document.addEventListener('animationend', function (e) {
  if (e.animationName === 'fade-out') {
      e.target.classList.remove('did-fade-in');
   }
});
div {
    border: 5px solid;
    padding: 10px;
}

div:hover {
    border-color: red;
}

.parent .child {
  display: none;
}

.parent:hover .child {
  display: block;
  animation: fade-in 1s;
}

.parent:not(:hover) .child.did-fade-in {
  display: block;
  animation: fade-out 1s;
}

@keyframes fade-in {
  from {
    opacity: 0;
  }
  to {
    opacity: 1;
  }
}

@keyframes fade-out {
  from {
    opacity: 1;
  }
  to {
    opacity: 0;
  }
}
<div class="parent">
    Parent
    <div class="child">
        Child
    </div>
</div>

Салман фон Аббас
источник
3
Спасибо за это. height: 0Трюк (для переходов) , упомянутых выше , кажется, не работает , потому что высота получает значение 0 на перепыла из перехода, но этот трюк , кажется, работает нормально.
Эллиот Винклер
41
Спасибо, очень полезно. Но как это исчезнуть?
Иллиоу
1
Первый абзац этого ответа не совсем имеет смысла. Браузеры не просто отключают все переходы сразу, как только вы используете это displayсвойство - на самом деле нет причин для этого. И даже если бы они сделали , почему анимация тогда работала? Вы также не можете использовать это displayсвойство в CSS-анимации.
BoltClock
7
Лучший ответ, невозможно с переходами, но да с анимацией.
Микель
6
Как насчет обратной анимации, то есть когда элемент должен медленно исчезать?
Зеленый
78

Я подозреваю, что причина, по которой переходы отключены, если они displayизменены, заключается в том, что на самом деле делает дисплей. Это не меняет ничего, что можно было бы плавно анимировать.

display: none;и visibility: hidden;это две совершенно разные вещи.
И то и другое делает элемент невидимым, но visibility: hidden;он все равно отображается в макете, но не так заметно .
Скрытый элемент по-прежнему занимает место и по-прежнему отображается как встроенный, либо как блок, либо как inline-блок, либо как таблица, или независимо от того, какой displayэлемент говорит ему отображать, и соответственно занимает пространство.
Другие элементы не перемещаются автоматически, чтобы занять это пространство. Скрытый элемент просто не отображает свои фактические пиксели на выходе.

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

displayэто не просто еще один визуальный атрибут.
Он устанавливает режим визуализации всего элемента, например, является ли это block, inline, inline-block, table, table-row, table-cell, list-item, или что угодно!
Каждый из них имеют очень разные последствия компоновки, и не было бы никакого разумного способа одушевленные или плавно переходить их (попробуйте представить себе плавный переход от blockк inlineили наоборот, к примеру!).

Вот почему переходы отключаются, если отображаемые изменения (даже если изменение относится к или от none- noneэто не просто невидимость, это собственный режим рендеринга элементов, который вообще не означает рендеринга!).

Joel_MMCC
источник
8
Какими бы хорошими ни были описанные выше решения, было очень приятно получить разумное объяснение, почему переходы не применяются к атрибутам отображения.
kqr
8
Я не согласен. Это может иметь полный смысл. Если display: none to display: блок возник немедленно в начале перехода, это было бы здорово. И для перехода назад, если он перешел с display: block на display: нет в конце перехода, это было бы идеально.
Кертис Яллоп
2
Если вы не представляете, как выглядит анимация из точки в прямоугольник, у вас есть проблемы. ОЧЕНЬ очевиден переход от незанятого пространства к занимающему прямоугольное пространство, например, вы делаете это каждый раз, когда мышью перетаскиваете прямоугольник, как в любом приложении. В результате этого сбоя, так много хаков с максимальной высотой и отрицательными полями, это смешно. Единственное, что работает, - это кэширование «реальной» высоты, а затем анимация от нуля до кэшированного значения с помощью JavaScript. Печальный.
Трийнко
2
Tryniko: display: none не меняет размер элемента на прямоугольник 0 x 0 - он удаляет его из DOM. Вы можете анимировать от прямоугольника до точки, анимируя свойства width и height до нуля, и тогда другие элементы будут обтекать его, как если бы он имел «display: none», но его атрибут «display» остался бы «block»; элемент все еще находится в DOM. Концепция анимации между отображением: блок и отображение: ни один не смешен: нет промежуточных состояний. Элемент либо существует в DOM, либо его нет, независимо от того, насколько он мал или невидим.
Стив Торп
1
Не смешно анимировать отдельные свойства. Дискретные свойства, такие как, displayне могут плавно переходить, как другие свойства, но это не означает, что время не имеет значения. Умение контролировать, когда происходит переход от одного disply:blockк display:noneдругому, очень важно. Точно так же, как @CurtisYallop описал это. Если я хочу , чтобы переход от opacity:1к opacity:0и затем изменить , display:blockчтобы display:noneя должен быть в состоянии сделать это.
Йенс
57

Вместо обратных вызовов, которых нет в CSS, мы можем использовать transition-delayсвойство.

#selector {
    overflow: hidden; // Hide the element content, while height = 0
    height: 0; opacity: 0;
    transition: height 0ms 400ms, opacity 400ms 0ms;
}
#selector.visible {
    height: auto; opacity: 1;
    transition: height 0ms 0ms, opacity 600ms 0ms;
}

Итак, что здесь происходит?

  1. Когда visibleкласс добавляется, как heightи opacityначать анимацию без задержки (0 мс), тем не менее heightзанимает 0 мс до полной анимации (эквивалент display: block) и opacityзанимает 600 мс.

  2. Когда visibleкласс удаляется, opacityзапускается анимация (задержка 0 мс, длительность 400 мс), а высота ожидает 400 мс и только затем мгновенно (0 мс) восстанавливает начальное значение (эквивалентно display: noneобратному вызову анимации).

Обратите внимание, этот подход лучше, чем те, которые используют visibility. В таких случаях элемент все еще занимает место на странице, и это не всегда подходит.

Для большего количества примеров, пожалуйста, обратитесь к этой статье .

Webars
источник
8
Удивлен, что у этого нет больше голосов - это умное решение так или иначе работает отлично.
фанфара
3
Это работает только с тем, height:100%что может разрушить макет в некоторых случаях. Отличное решение, если это не проблема. Один из немногих работающих двунаправленных.
Фабиан фон Эллертс
Это замечательно! Мне удалось упростить его еще больше в моем случае, потому что я хотел, чтобы время анимации затухания было таким же, как и время затухания. Вместо того, чтобы использовать transition: height 0ms 0ms, opacity 600ms 0ms, я просто использовал transition-delay: 0s.
Джейкоб Локард
52

display не является одним из свойств, над которыми работает переход.

См. Свойства анимируемых CSS для списка свойств CSS, к которым могут быть применены переходы. См. « Значения и единицы измерения CSS», уровень 4, «Объединение значений: интерполяция, сложение и накопление», чтобы узнать, как они интерполируются.

До CSS 3 был указан в 9.1. Свойства из CSS (просто закройте всплывающее окно с предупреждением)

Я также пытался использовать высоту, но это с треском провалилось.

В прошлый раз, когда мне пришлось это сделать, я использовал max-heightвместо этого свойство, которое можно анимировать (хотя это было немного хаком, оно работало), но имейте в виду, что это может быть очень неудобно для сложных страниц или пользователей с низким уровнем мобильности устройства.

robocat
источник
Ссылка больше не указывает прямо на раздел свойств анимации.
Эндрю Лам
1
@AndrewLam Исправлено. Спасибо.
Робокат
34

Теперь вы можете добавить собственную анимацию в свойство блока.

@keyframes showNav {
  from {opacity: 0;}
  to {opacity: 1;}
}
.subnav-is-opened .main-nav__secondary-nav {
  display: block;
  animation: showNav 250ms ease-in-out both;
}

демонстрация

В этой демонстрации подменю изменяется с display:noneна display:blockи все еще удается исчезнуть.

Маниш Прадхан
источник
Должен myfirstбыть showNavздесь? А как насчет Firefox? К сожалению, я не могу найти что-то связанное на демонстрационной странице, которую вы упоминаете.
Себастьян фон Меер
Спасибо @SebastianG. Я сделал исправление и добавил дополнительную информацию выше.
Маниш Прадхан
@Sebastian vom Meer: более старые версии Firefox требуют префикса поставщика "-moz-", см. Отредактированный код
Herr_Schwabullek
23
Если я не пропустил что-то, ссылка "демо" больше не показывает переход подменю.
Реалистичная
1
Правильный переход для чего-то, что не занимает места (как в случае с display: none), к чему-то, что занимает пространство (display: block), является расширением измерений, а не постепенным расширением. Если бы это был вопрос видимости, скрытый (который занимает пространство, но не видимый) для видимого, то размер остается тем же, и уместность является подходящей. Ни один из этих ответов не решает проблему.
Трийнко
21

Согласно рабочему проекту W3C от 19 ноября 2013 года, display объект не подлежит анимации . К счастью, visibilityэто анимация. Вы можете связать его переход с переходом непрозрачности ( JSFiddle ):

  • HTML:

    <a href="http://example.com" id="foo">Foo</a>
    <button id="hide-button">Hide</button>
    <button id="show-button">Show</button>
  • CSS:

    #foo {
        transition-property: visibility, opacity;
        transition-duration: 0s, 1s;
    }
    
    #foo.hidden {
        opacity: 0;
        visibility: hidden;
        transition-property: opacity, visibility;
        transition-duration: 1s, 0s;
        transition-delay: 0s, 1s;
    }
  • JavaScript для тестирования:

    var foo = document.getElementById('foo');
    
    document.getElementById('hide-button').onclick = function () {
        foo.className = 'hidden';
    };
    
    document.getElementById('show-button').onclick = function () {
        foo.className = '';
    };

Обратите внимание, что если вы просто сделаете ссылку прозрачной, без настроек visibility: hidden, тогда она останется кликабельной.

feklee
источник
1
я не вижу никакого перехода вообще в примере с jsfiddle
Gino
@ Джино Я исправил это, изменив 0на 0s. Судя по всему, в прошлом браузер, который я использовал для тестирования, поддерживал единичные ноль раз. Тем не менее, единичные времена не являются частью Рекомендации кандидата W3C от 29 сентября 2016 года .
Фекли
Это должно быть одобрено больше. Я нашел это одним из лучших решений.
Артур Тарасов
Использование задержки - просто лучшая логика, чтобы понять, как это работает. Оживи и спрячь. Показать и оживить. Идеальное решение для меня
Бруно Питтели Гонсалвес
15

Редактировать: отображение не применяется в этом примере.

@keyframes hide {
  0% {
    display: block;
    opacity: 1;
  }
  99% {
    display: block;
  }
  100% {
    display: none;
    opacity: 0;
  }
}

Что происходит выше, так это то, что на 99% анимации дисплей блокируется, а прозрачность исчезает. В последний момент свойство display установлено в none.

И самый важный бит - сохранить последний кадр после окончания анимации, используя animation-fill-mode: forwards

.hide {
   animation: hide 1s linear;
   animation-fill-mode: forwards;
}

Вот два примера: https://jsfiddle.net/qwnz9tqg/3/

Pawel
источник
с этим решением display: noneне работает то?
Барт Каликсто
Должен быть «animation-fill-mode: forwards», а не «forward»
Alex
Изменения должны состоять из шести символов, и я могу только предложить редактировать, отсюда и комментарий
Alex
1
@ Алекс Хорошо. Опечатка исправлена. Что интересно, мой ответ даже не работает должным образом, но логично предположить, что так и будет, поэтому я буду держать его, пока браузеры его не поддержат.
Павел
3
Как вы можете видеть в этой скрипке с установленными курсорами display: none, фактически никогда не реализуется. jsfiddle.net/3e6sduqh
robstarbuck
14

Мой хитрый трюк с JavaScript состоит в том, чтобы разделить весь сценарий на две разные функции !

Для подготовки объявляется одна глобальная переменная и определяется один обработчик события:

  var tTimeout;
  element.addEventListener("transitionend", afterTransition, true);//firefox
  element.addEventListener("webkitTransitionEnd", afterTransition, true);//chrome

Затем, когда скрываю элемент, я использую что-то вроде этого:

function hide(){
  element.style.opacity = 0;
}

function afterTransition(){
  element.style.display = 'none';
}

Для повторного появления элемента я делаю что-то вроде этого:

function show(){
  element.style.display = 'block';
  tTimeout = setTimeout(timeoutShow, 100);
}

function timeoutShow(){
  element.style.opacity = 1;
}

Это работает, пока!

Саша Миленкович
источник
Это работает из-за временной задержки, а не потому, что команды javascript находятся в отдельных функциях. Временные задержки кажутся хорошим решением во многих случаях :)
10

Я столкнулся с этим сегодня, с position: fixedмодалом, который я использовал повторно. Я не мог сохранить это display: noneи затем оживить это, поскольку это просто появилось, и и z-index(отрицательные ценности, и т.д.) также сделал странные вещи.

Я также использовал height: 0to height: 100%, но он работал только когда появился модал. Это так же, как если бы вы использовали left: -100%или что-то.

Тогда меня поразило, что был простой ответ. И вуаля:

Во-первых, ваш скрытый модал. Обратите внимание на heightis 0и проверьте heightобъявление в переходах ... оно имеет значение 500ms, которое длиннее, чем мой opacityпереход . Помните, что это влияет на исходящий переход затухания: возврат модального в его состояние по умолчанию.

#modal-overlay {
    background: #999;
    background: rgba(33,33,33,.2);
    display: block;
    overflow: hidden;
    height: 0;
    width: 100%;
    position: fixed;
    top: 0;
    left: 0;
    opacity: 0;
    z-index: 1;
    -webkit-transition: height 0s 500ms, opacity 300ms ease-in-out;
       -moz-transition: height 0s 500ms, opacity 300ms ease-in-out;
            -ms-transition: height 0s 500ms, opacity 300ms ease-in-out;
         -o-transition: height 0s 500ms, opacity 300ms ease-in-out;
        transition: height 0s 500ms, opacity 300ms ease-in-out;
}

Во-вторых, ваш видимый модал. Скажем, вы устанавливаете .modal-activeна body. Теперь heightэто 100%и мой переход тоже изменился. Я хочу, heightчтобы это было немедленно изменено, и opacityчтобы взять 300ms.

.modal-active #modal-overlay {
    height: 100%;
    opacity: 1;
    z-index: 90000;
    -webkit-transition: height 0s, opacity 300ms ease-in-out;
       -moz-transition: height 0s, opacity 300ms ease-in-out;
        -ms-transition: height 0s, opacity 300ms ease-in-out;
         -o-transition: height 0s, opacity 300ms ease-in-out;
            transition: height 0s, opacity 300ms ease-in-out;
}

Вот и все, это работает как шарм.

hotmeteor
источник
Проголосование за ваш стиль выравнивания свойств с префиксом продавца George
Джордж Грин
9

Принимая во внимание некоторые из этих ответов и некоторые предложения в других местах, следующее прекрасно подходит для всплывающих меню (я использую это с Bootstrap  3, в частности):

nav .dropdown-menu {
    display: block;
    overflow: hidden;
    max-height: 0;
    opacity: 0;
    transition: max-height 500ms, opacity 300ms;
    -webkit-transition: max-height 500ms, opacity 300ms;
}
nav .dropdown:hover .dropdown-menu {
    max-height: 500px;
    opacity: 1;
    transition: max-height 0, opacity 300ms;
    -webkit-transition: max-height 0, opacity 300ms;
}

Вы также можете использовать heightвместо, max-heightесли вы указываете оба значения, так height:autoкак не допускается с transitions. Значение наведения max-heightдолжно быть больше, чем heightможет быть меню.

Edyn
источник
3
Это хороший трюк, но есть и недостаток. Время перехода зависит от высоты. Если есть несколько меню с переменной высотой, элементы с высотой ближе к максимальной высоте будут хорошо анимироваться. Однако, более короткие из них будут анимироваться слишком быстро, давая непоследовательный опыт.
пользователь
8

Я нашел лучший способ решить эту проблему, вы можете использовать CSS-анимацию и сделать свой удивительный эффект для отображения элементов.

    .item {
     display: none;
}

.item:hover {
     display: block;
     animation: fade_in_show 0.5s
}

@keyframes fade_in_show {
     0% {
          opacity: 0;
          transform: scale(0)
     }
     100% {
          opacity: 1;
          transform: scale(1)
     }
}
irgfx
источник
Спасибо за этот полезный совет. Он отлично работает.
Седат Кумчу
6

Я сталкивался с этой проблемой несколько раз, и теперь просто пошел с:

.block {
  opacity: 1;
  transition: opacity 250ms ease;
}

.block--invisible {
  pointer-events: none;
  opacity: 0;
}

При добавлении класса block--invisibleцелые элементы не будут кликабельными, но все элементы за ним будут из-за того, pointer-events:noneчто поддерживается всеми основными браузерами (нет IE <11).

DominikAngerer
источник
Можете ли вы привести это в пример, пожалуйста?
GarethAS
1
Это хорошо работает, но следует отметить, что события указателя не работают с IE ниже 11
user1702965
добавлена ​​заметка для IE ниже 11
DominikAngerer
Если вам нужно, чтобы элемент был указан поверх всего (например, меню), это, честно говоря, самый чистый способ сделать это сейчас, когда в 2019 году поддержка будет pointer-events
Джош Дэвенпорт
5

Изменить overflow:hiddenна overflow:visible. Это работает лучше. Я использую так:

#menu ul li ul {
    background-color:#fe1c1c;
    width:85px;
    height:0px;
    opacity:0;
    box-shadow:1px 3px 10px #000000;
    border-radius:3px;
    z-index:1;
    -webkit-transition:all 0.5s ease;
    -moz-transition:all 0.6s ease;
}

#menu ul li:hover ul  {
    overflow:visible;
    opacity:1;
    height:140px;
}

visibleлучше, потому что overflow:hiddenдействовать так же, как display:none.

Иисус
источник
Этот был билет для меня. Спасибо!
Дэн Левенхерц
5

JavaScript не требуется, и не требуется огромная максимальная высота. Вместо этого установите свои max-heightтекстовые элементы и используйте относительную единицу шрифта, такую ​​как remилиem . Таким образом, вы можете установить максимальную высоту больше, чем ваш контейнер, избегая задержки или «всплывающих окон» при закрытии меню:

HTML

<nav>
  <input type="checkbox" />
  <ul>
    <li>Link 1</li>
    <li>Link 1</li>
    <li>Link 1</li>
    <li>Link 1</li>
  </ul>
</nav>

CSS

nav input + ul li { // Notice I set max-height on li, not ul
   max-height: 0;
}

nav input:checked + ul li {
   max-height: 3rem; // A little bigger to allow for text-wrapping - but not outrageous
}

Смотрите пример здесь: http://codepen.io/mindfullsilence/pen/DtzjE

mindfullsilence
источник
Подобно этому вы можете установить высоту строки для вашего текста и преобразовать его в ноль. Если внутри есть только текст, контейнер будет скрыт.
vicmortelmans
Почему так мало голосов? Это действительно хороший ответ, и я могу использовать его.
Mwilcox
@mwilcox Поскольку он использует фиксированную высоту, что плохо при работе с динамическим контентом (даже предполагаемая высота). И это полезно только для текстового контента.
Фабиан фон Эллертс
5

После написания принятого ответа от Гильермо спецификация CSS-перехода 2012-04-03 изменила поведение перехода видимости, и теперь можно решить эту проблему более коротким способом , без использования transition-delay:

.myclass > div {
                   transition:visibility 1s, opacity 1s;
                   visibility:hidden;  opacity:0
               }
.myclass:hover > div
               {   visibility:visible; opacity:1 }

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

Работающую версию см. В моем блоге CSS Transition Visibility .

Напишите название вопроса «Переходы на дисплее: собственность» и в ответ на комментарии Руи Маркеса и Джоша к принятому ответу:

Это решение работает в тех случаях, когда оно не имеет значения, если используется свойство display или visibility (как, вероятно, имело место в этом вопросе).

Он не удалит элемент полностью display:none, просто сделает его невидимым, но он все равно останется в потоке документа и повлияет на положение следующих элементов.

Переходы, которые полностью удаляют элемент, подобный элементу, display:noneмогут быть выполнены с использованием высоты (как указано в других ответах и ​​комментариях), max-height или margin-top / bottom, но также см. Как я могу изменить высоту: 0; по высоте: авто; используя CSS? и мой пост в блоге Временные решения для переходов CSS на свойствах Display и Height .

В ответ на комментарий от GeorgeMillo: необходимы оба свойства и оба перехода: свойство opacity используется для создания анимации постепенного появления и исчезновения, а также свойства видимости, чтобы элемент не реагировал на события мыши. Необходимы переходы по непрозрачности для визуального эффекта и по видимости, чтобы отложить скрытие до завершения затухания.

Хельмут Эммельманн
источник
4

Я наконец нашел решение для меня, комбинируя opacityс position absolute(не занимать место, когда спрятано).

.toggle {
  opacity: 0;
  position: absolute;
  transition: opacity 0.8s;
}

.parent:hover .toggle {
  opacity: 1;
  position: static;
}
Дамжан Павлица
источник
4

Я подозреваю, что любой, кто только начинает переходы CSS, быстро обнаруживает, что они не работают, если вы одновременно изменяете свойство display (block / none). Одним из обходных путей, который еще не был упомянут, является то, что вы можете продолжать использовать, display:block/noneчтобы скрыть / показать элемент, но установите его непрозрачность равной 0, чтобы, даже когда он был display:block, он все еще невидим.

Затем, чтобы добавить его, добавьте еще один класс CSS, например «on», который устанавливает непрозрачность равной 1 и определяет переход для непрозрачности. Как вы могли себе представить, вам придется использовать JavaScript, чтобы добавить этот класс «on» к элементу, но по крайней мере вы все еще используете CSS для фактического перехода.

PS Если вы оказались в ситуации, когда вам нужно выполнить оба действия display:blockи добавить класс «on», в то же время отложите последнее с помощью setTimeout. В противном случае браузер просто видит обе вещи как происходящие одновременно и отключает переход.

Ларри Герндт
источник
Отлично, спасибо! Я написал другой ответ с примером, который на самом деле работает display:none.
Моджуба
4

Это так же просто, как следующее :)

@keyframes fadeout {
    0% { opacity: 1; height: auto; }
    90% { opacity: 0; height: auto; }
    100% { opacity: 0; height: 0;
}
animation: fadeout linear 0.5s 1 normal forwards !important;

Получите, чтобы это исчезло, и затем сделайте это height 0;. Также обязательно используйте форварды, чтобы они оставались в конечном состоянии.

Велько Симакович
источник
Это немедленно
Шон Т
2

Это решение имеет отличную совместимость, и я еще не видел его:

.hidden-element {
  position: absolute;
  z-index: -1;
  pointer-events: none;
  visibility: hidden;
  opacity: 0;
  transition: visibility 0s, opacity .5s ease-out;
}

.hidden-element.visible {
  position: static;
  z-index: auto;
  pointer-events: auto;
  visibility: visible;
  opacity: 1;
}

Объяснение : он использует visibility: hiddenхитрость (которая совместима с «покажи и анимируй» за один шаг), но он использует комбинацию, position: absolute; z-index: -1; pointer-events: none;чтобы убедиться, что скрытый контейнер не занимает место и не отвечает на взаимодействия с пользователем .

Кристоф Маруа
источник
1
Но изменение positionвсе равно заставит элемент дергаться, не так ли?
Arsylum
Ну, конечно: position: absoluteозначает, что элемент не занимает места, как описано в объяснении. Когда он переключается position: staticи появляется, он будет занимать пространство, как обычный элемент, что является точкой этого вопроса. Я предлагаю вам попробовать!
Кристоф Маруа
2
Я сделал. Но если я правильно понял, вопрос был о переходах . Как в «плавной анимации».
Arsylum
2

Вы можете заставить это работать так, как вы ожидали - используя отображение, - но вам нужно настроить браузер, чтобы заставить его работать, используя либо Javascript, либо, как другие предлагали причудливый трюк с одним тегом внутри другого. Мне плевать на внутренний тег, так как он еще больше усложняет CSS и размеры, поэтому вот решение Javascript:

https://jsfiddle.net/b9chris/hweyecu4/17/

Начиная с коробки вроде:

<div id="box" class="hidden">Lorem</div>

Скрытая коробка.

div.hidden {
    display: none;
}
#box {
    transition: opacity 1s;
}

Мы собираемся использовать трюк, найденный в соответствующем вопросе, проверяя offsetHeight, чтобы мгновенно регулировать скорость браузера:

https://stackoverflow.com/a/16575811/176877

Во-первых, библиотека, формализующая вышеупомянутый трюк:

$.fn.noTrnsn = function () {
    return this.each(function (i, tag) {
        tag.style.transition = 'none';
    });
};
$.fn.resumeTrnsn = function () {
    return this.each(function (i, tag) {
        tag.offsetHeight;    
        tag.style.transition = null;
    });
};

Далее, мы собираемся использовать его, чтобы показать коробку, и добавить ее:

$('#button').on('click', function() {
    var tag = $('#box');
    if (tag.hasClass('hidden'))
        tag.noTrnsn().removeClass('hidden')
        .css({ opacity: 0 })
        .resumeTrnsn().css({ opacity: 1 });
    else
        tag.css({ opacity: 0 });
});

Это исчезает из коробки и выходит. Так, .noTrnsn()выключает переходы, то мы удаляем hiddenкласс, который переворачивает displayс noneего умолчанию block. Затем мы устанавливаем непрозрачность на 0, чтобы подготовиться к появлению. Теперь, когда мы установили сцену, мы снова включаем переходы с помощью .resumeTrnsn(). И, наконец, начните переход, установив непрозрачность на 1.

Без библиотеки и отображение, и изменение непрозрачности получили бы нежелательные результаты. Если бы мы просто удалили вызовы библиотеки, мы бы вообще не получили переходов.

Обратите внимание, что вышеприведенное не устанавливает display снова в none в конце анимации затухания. Мы можем полюбоваться, хотя. Давайте сделаем это с тем, который вырастает и растет в высоту от 0.

Необычные!

https://jsfiddle.net/b9chris/hweyecu4/22/

#box {
    transition: height 1s, opacity 1s;
}

Сейчас мы переносим как высоту, так и непрозрачность. Обратите внимание, что мы не устанавливаем высоту, что означает, что это значение по умолчанию auto. Традиционно это не может быть перенесено - переход от автоматического значения к пикселю (например, 0) не даст вам никакого перехода. Мы собираемся обойти это с библиотекой и еще одним библиотечным методом:

$.fn.wait = function (time, fn) {
    if (time)
        this.delay(time);
    if (!fn)
        return this;

    var _this = this;
    return this.queue(function (n) {
        fn.call(_this);
        n();
    });
};

Это удобный метод, который позволяет нам участвовать в существующей очереди jQuery fx / animation, не требуя какой-либо инфраструктуры анимации, которая теперь исключена в jQuery 3.x. Я не собираюсь объяснять, как работает jQuery, но достаточно сказать, что .queue()и возможности .stop(), предоставляемые jQuery, помогают нам не допустить, чтобы наши анимации наступали друг на друга.

Давайте оживим эффект слайда.

$('#button').on('click', function() {
    var tag = $('#box');
    if (tag.hasClass('hidden')) {
        // Open it
        // Measure it
        tag.stop().noTrnsn().removeClass('hidden').css({
            opacity: 0, height: 'auto'
        });
        var h = tag.height();
        tag.css({ height: 0 }).resumeTrnsn()
        // Animate it
        .css({ opacity: 1, height: h })
        .wait(1000, function() {
            tag.css({ height: 'auto' });
        });
    } else {
        // Close it
        // Measure it
        var h = tag.noTrnsn().height();
        tag.stop().css({ height: h })
        .resumeTrnsn()
        // Animate it
        .css({ opacity: 0, height: 0 })
        .wait(1000, function() {
            tag.addClass('hidden');
        });
    }
});

Этот код начинается с проверки #boxтого, скрыт ли он в данный момент, с проверки его класса. Но он выполняет больше, используя wait()библиотечный вызов, добавляя hiddenкласс в конце анимации скольжения / затухания, которую вы ожидаете найти, если она на самом деле скрыта - чего не мог сделать вышеупомянутый простой пример. Это также позволяет снова и снова отображать / скрывать элемент, что было ошибкой в ​​предыдущем примере, поскольку скрытый класс никогда не восстанавливался.

Вы также можете увидеть изменения CSS и класса, вызываемые после, .noTrnsn()чтобы в целом установить сцену для анимации, включая измерение, например, измерение конечной высоты #boxбез показа пользователю, перед вызовом .resumeTrnsn()и анимацию этого полностью настроенного набора. этап к своей цели CSS значения.

Старый ответ

https://jsfiddle.net/b9chris/hweyecu4/1/

Вы можете сделать это при клике:

function toggleTransition() {
  var el = $("div.box1");

  if (el.length) {
    el[0].className = "box";
    el.stop().css({maxWidth: 10000}).animate({maxWidth: 10001}, 2000, function() {
        el[0].className = "box hidden";
    });
  } else {
    el = $("div.box");
    el[0].className = "box";
    el.stop().css({maxWidth: 10001}).animate({maxWidth: 10000}, 50, function() {
        el[0].className = "box box1";
    });
  }

  return el;
}

someTag.click(toggleTransition);

CSS это то, что вы догадались бы:

.hidden {
    display: none;
}
.box {
    width: 100px;
    height: 100px;
    background-color: blue;
    color: yellow;
    font-size: 18px;
    left: 20px;
    top: 20px;
    position: absolute;
    -webkit-transform-origin: 0 50%;
    transform-origin: 0 50%;
    -webkit-transform: scale(.2);
    transform: scale(.2);
    -webkit-transition: transform 2s;
    transition: transform 2s;
}
.box1{
    -webkit-transform: scale(1);
    transform: scale(1);
}

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

Примечание: я злоупотребляю .animate(maxWidth)здесь, чтобы избежать setTimeoutусловий гонки. setTimeoutбыстро вводить скрытые ошибки, когда вы или кто-то другой обнаруживает код, не подозревая об этом. .animate()может быть легко убит с .stop(). Я просто использую его, чтобы поместить задержку в 50 мс или 2000 мс в стандартную очередь fx, где легко найти / решить другие кодеры, основанные на этом.

Крис Москини
источник
1

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

Оказывается, visibilityсвойство CSS имеет значение, collapseкоторое обычно используется для элементов таблицы. Однако, если он используется с любыми другими элементами, он фактически делает их скрытыми , почти так же, какdisplay: hidden с добавленной возможностью, что элемент не занимает места, и вы все равно можете анимировать рассматриваемый элемент.

Ниже приведен простой пример этого в действии.

function toggleVisibility() {
  let exampleElement = document.querySelector('span');
  if (exampleElement.classList.contains('visible')) {
    return;
  }
  exampleElement.innerHTML = 'I will not take up space!';
  exampleElement.classList.toggle('hidden');
  exampleElement.classList.toggle('visible');
  setTimeout(() => {
    exampleElement.classList.toggle('visible');
    exampleElement.classList.toggle('hidden');
  }, 3000);
}
#main {
  display: flex;
  flex-direction: column;
  width: 300px;
  text-align: center;
}

.hidden {
  visibility: collapse;
  opacity: 0;
  transition: visibility 2s, opacity 2s linear;
}

.visible {
  visibility: visible;
  opacity: 1;
  transition: visibility 0.5s, opacity 0.5s linear;
}
<div id="main">
  <button onclick="toggleVisibility()">Click Me!</button>
  <span class="hidden"></span>
  <span>I will get pushed back up...</span>
</div>

Deadmano
источник
1

Самое простое универсальное решение проблемы: не стесняйтесь указывать display:noneв своем CSS, однако вам придется изменить его на block(или что-то еще) с помощью JavaScript, а затем вам также нужно будет добавить класс к вашему элементу, который на самом деле выполняет переход с помощью setTimeout () . Это все.

То есть:

<style>
    #el {
        display: none;
        opacity: 0;
    }
    #el.auto-fade-in {
        opacity: 1;
        transition: all 1s ease-out; /* Future, future, please come sooner! */
        -webkit-transition: all 1s ease-out;
        -moz-transition: all 1s ease-out;
        -o-transition: all 1s ease-out;
    }
</style>

<div id=el>Well, well, well</div>

<script>
    var el = document.getElementById('el');
    el.style.display = 'block';
    setTimeout(function () { el.className = 'auto-fade-in' }, 0);
</script>

Это было проверено в последних нормальных браузерах. Очевидно, что это не должно работать в Internet Explorer 9 или более ранней версии.

mojuba
источник
1

Я думаю, у SalmanPK есть самый близкий ответ. Он выцветает или исчезает с помощью следующих CSS-анимаций. Однако свойство display не анимирует плавно, только непрозрачность.

@-webkit-keyframes fadeIn {
    from { opacity: 0; }
      to { opacity: 1; }
}

@-webkit-keyframes fadeOut {
    from { opacity: 1; }
      to { opacity: 0; }
}

Если вы хотите анимировать элемент, перемещающийся из блока отображения, чтобы ничего не отображать, я не вижу, чтобы это было возможно только с помощью CSS. Вы должны получить высоту и использовать CSS-анимацию, чтобы уменьшить высоту. Это возможно с помощью CSS, как показано в примере ниже, но было бы сложно узнать точные значения высоты, которые нужно анимировать для элемента.

jsFiddle пример

CSS

@-webkit-keyframes pushDown {
  0% {
    height: 10em;
  }
  25% {
    height: 7.5em;
  }
  50% {
    height: 5em;
  }
  75% {
    height: 2.5em;
  }
  100% {
    height: 0em;
  }
}

.push-down {
    -webkit-animation: pushDown 2s forwards linear;
}

JavaScript

var element = document.getElementById("element");

// Push item down
element.className = element.className + " push-down";
svnm
источник
1

Вы можете сделать это с событиями перехода, поэтому вы создаете два CSS-класса для перехода, один из которых содержит анимацию, а другой - отображение состояния отсутствия. И вы переключаете их после окончания анимации? В моем случае я могу снова показать div, если я нажму кнопку, и удаляю оба класса.

Попробуйте фрагмент ниже ...

$(document).ready(function() {
  // Assign transition event
  $("table").on("animationend webkitAnimationEnd", ".visibility_switch_off", function(event) {
    // We check if this is the same animation we want
    if (event.originalEvent.animationName == "col_hide_anim") {
      // After the animation we assign this new class that basically hides the elements.
      $(this).addClass("animation-helper-display-none");
    }

  });

  $("button").click(function(event) {

    $("table tr .hide-col").toggleClass(function() {
      // We switch the animation class in a toggle fashion...
      // and we know in that after the animation end, there
      // is will the animation-helper-display-none extra
      // class, that we nee to remove, when we want to
      // show the elements again, depending on the toggle
      // state, so we create a relation between them.
      if ($(this).is(".animation-helper-display-none")) {
        // I'm toggling and there is already the above class, then
        // what we want it to show the elements , so we remove
        // both classes...
        return "visibility_switch_off animation-helper-display-none";
      }
      else {
        // Here we just want to hide the elements, so we just
        // add the animation class, the other will be added
        // later be the animationend event...
        return "visibility_switch_off";
      }
    });
  });
});
table th {
  background-color: grey;
}

table td {
  background-color: white;
  padding: 5px;
}

.animation-helper-display-none {
  display: none;
}

table tr .visibility_switch_off {
  animation-fill-mode: forwards;
  animation-name: col_hide_anim;
  animation-duration: 1s;
}

@-webkit-keyframes col_hide_anim {
  0% {opacity: 1;}
  100% {opacity: 0;}
}

@-moz-keyframes col_hide_anim {
  0% {opacity: 1;}
  100% {opacity: 0;}
}

@-o-keyframes col_hide_anim {
  0% {opacity: 1;}
  100% {opacity: 0;}
}

@keyframes col_hide_anim {
  0%   {opacity: 1;}
  100% {opacity: 0;}
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table>
  <theader>
    <tr>
      <th>Name</th>
      <th class='hide-col'>Age</th>
      <th>Country</th>
    </tr>
  </theader>
  <tbody>
    <tr>
      <td>Name</td>
      <td class='hide-col'>Age</td>
      <td>Country</td>
    </tr>
  </tbody>
</table>

<button>Switch - Hide Age column with fadeout animation and display none after</button>

Miguel
источник
0

Если вы используете jQuery для установки классов, это будет работать на 100%:

$(document).ready(function() {
  $('button').click(function() {
    var container = $('.container');
    
    if (!container.hasClass('active')) {
      container.addClass('show').outerWidth();
      container.addClass('active');
    }
    else {
      container.removeClass('active').one('transitionend', function() {
        container.removeClass('show');
      });
    }
  });
});
.container {
  display: none;
  opacity: 0;
  transition: opacity 0.3s ease;
}

.container.show {
  display: flex;
}
 
.container.active {
  opacity: 1;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button type="button">Toggle</button>

<div class="container">
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
</div>

Конечно, вы можете просто использовать jQuery .fadeIn()и .fadeOut()функции, но преимущество установки классов вместо этого в том случае, если вы хотите перейти к отображаемому значению, отличному от block(как это по умолчанию с .fadeIn()и.fadeOut() ).

Здесь я перехожу к отображению flexс хорошим эффектом затухания.

GSTAR
источник
0

Вместо использования displayвы можете хранить элемент «вне экрана» до тех пор, пока он вам не понадобится, а затем установить его положение там, где вам нужно, и одновременно преобразовать его. Это поднимает целый ряд других проблем дизайна, поэтому ваш пробег может варьироваться.

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

Питер Мортенсен
источник
0

Вы можете просто использовать видимость CSS : скрытый / видимый вместо отображения : нет / блок

div {
    visibility:hidden;
    -webkit-transition: opacity 1s ease-out;
    -moz-transition: opacity 1s ease-out;
    -o-transition: opacity 1s ease-out;
    transition: opacity 1s ease-out;
    opacity: 0;
}

parent:hover > div {
    opacity: 1;
    visibility: visible;
}
foxdanni
источник
5
Это оставляет место, хотя, оставляя пустую дыру. Если вы хотите свернуть пространство, вам нужно оживить высоту или другое свойство.
Марси Саттон
0

Я запустил скелетный проект с открытым исходным кодом под названием Toggle Display Animate .

Этот каркасный помощник позволит вам легко имитировать jQuery show / hide, но с анимацией перехода в CSS 3.

Он использует переключатели классов, поэтому вы можете использовать любые методы CSS для элементов, кроме display: none | block | table | inline и т. Д., А также другие альтернативные варианты использования, которые можно придумать.

Его основное предназначение - для состояний переключения элементов, и он поддерживает состояние возврата, при котором скрытие объекта позволяет запускать ключевой кадр в обратном порядке или воспроизводить альтернативную анимацию для скрытия элемента.

Большая часть разметки для концепции, над которой я работаю, - это CSS, и на самом деле очень мало JavaScript используется.

Здесь есть демо: http://marcnewton.co.uk/projects/toggle-display-animate/

Марк
источник