Переходы на дисплее: свойство - PullRequest
1256 голосов
/ 26 июля 2010

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

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

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

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

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

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

Все и любые предложения приветствуются.

Ответы [ 31 ]

1201 голосов
/ 04 августа 2011

Вы можете объединить два или более переходов, и 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)

Подробнее в этой статье

737 голосов
/ 26 июля 2010

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

Я выполнил эффект, поместив оба <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;
}
242 голосов
/ 17 февраля 2012

На момент написания этой статьи все основные браузеры отключали переходы 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 - Метод, который также поддерживает затухание:

(требуется JS)

// 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>
64 голосов
/ 15 июня 2012

Я подозреваю, что причина того, что переходы отключены, если «дисплей» изменяется, из-за того, что на самом деле делает дисплей.Он не меняет все, что можно плавно анимировать.

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

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

“display”Это не просто еще один визуальный атрибут.Он устанавливает весь режим рендеринга элемента, например, блок, встроенный блок, встроенный блок, таблица, строка таблицы, ячейка таблицы, элемент списка или любой другой!У каждого из них очень разные разветвления разметки, и не было бы разумного способа анимировать или плавно перевести их (например, попробуйте представить плавный переход от «блока» к «встроенному» или наоборот!).

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

49 голосов
/ 23 сентября 2011

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

См. https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_animated_properties для списка свойств CSS, к которым могут быть применены переходы. См. https://drafts.csswg.org/css-values-4/#combining-values, как они интерполируются.

До CSS3 было указано в https://www.w3.org/TR/2017/WD-css-transitions-1-20171130/#animatable-css (просто закройте всплывающее окно с предупреждением)

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

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

35 голосов
/ 30 июля 2014

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

@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 и все еще может исчезать.

27 голосов
/ 26 мая 2018

Вместо обратных вызовов, которых нет в 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: 100%; 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 мс) восстанавливает начальное значение (эквивалентное * 1021).* в анимации обратного вызова).

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

Для получения дополнительной информации см. Эту статью .

20 голосов
/ 02 февраля 2014

Согласно W3C Working Draft 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, тогда она останется кликабельной.

13 голосов
/ 15 декабря 2012

Мой хитрый трюк с 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;
}

Пока работает!

12 голосов
/ 30 октября 2015

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

@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/

...