Transições no display: propriedade

Atualmente, estou projetando uma espécie de menu suspenso de mega CSS – basicamente um menu suspenso apenas CSS, mas que contém diferentes tipos de conteúdo.

No momento, parece que o CSS3 Transitions não se aplica à propriedade ‘display’ , ou seja, você não pode fazer qualquer tipo de transição de display: none para display: block (ou qualquer combinação).

Alguém pode pensar em uma maneira de o menu de segundo nível do exemplo acima aparecer quando alguém passa por cima de um dos itens de menu de nível superior?

Estou ciente de que você pode usar transições na visibility: property, mas não consigo pensar em uma maneira de utilizá-la com eficiência.

Eu também tentei usar altura, mas isso só falhou miseravelmente.

Eu também estou ciente de que é trivial conseguir isso usando JavaScript, mas eu queria me desafiar a usar apenas CSS e acho que estou chegando um pouco curto.

Todas e quaisquer sugestões mais bem-vindas.

Você pode concatenar duas transições ou mais, e visibility é o que é útil desta vez.

 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; } 
 
  • Item 1
  • Item 2
  • Item 3

Você precisa ocultar o elemento por outros meios para que isso funcione.

Eu realizei o efeito posicionando os dois

s absolutamente e definindo o oculto para opacity: 0 .

Se você ainda alternar a propriedade de display de none para block , sua transição em outros elementos não ocorrerá.

Para contornar isso, sempre permita que o elemento seja display: block , mas oculte o elemento ajustando qualquer um destes meios:

  1. Ajuste a height para 0 .
  2. Defina a opacity para 0 .
  3. Posicione o elemento fora do quadro de outro elemento que tenha overflow: hidden .

Provavelmente há mais soluções, mas você não pode realizar uma transição se você alternar o elemento para display: none . Por exemplo, você pode tentar tentar algo assim:

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

Mas isso não vai funcionar. Pela minha experiência, descobri que isso não faz nada.

Por causa disso, você sempre precisará manter a display: block do elemento display: block – mas você pode contornar isso fazendo algo assim:

 div { transition: opacity 1s ease-out; opacity: 0; height: 0; overflow: hidden; } div.active { opacity: 1; height: auto; } 

No momento deste post, todos os principais navegadores desativam as transições CSS se você tentar alterar a propriedade de display , mas as animações CSS ainda funcionam bem para que possamos usá-las como uma alternativa.

Exemplo de código: – (Você pode aplicá-lo ao seu menu de acordo) Demonstração

Adicione o seguinte CSS à sua folha de estilo: –

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

Em seguida, aplique a animação fadeIn ao filho em foco pai: – (e, claro, display: block set display: block )

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

Eu suspeito que a razão pela qual as transições são desabilitadas se “display” é alterado é por causa do que a canvas realmente faz. Não muda nada que possa ser suavemente animado.

“Display: none;” e “visibility: hidden;” são duas coisas completamente diferentes. Ambos têm o efeito de tornar o elemento invisível, mas com “visibilidade: oculto”, ele ainda é renderizado no layout, mas não visivelmente . O elemento oculto ainda ocupa espaço, e ainda é renderizado em linha ou como um bloco ou bloco-em-linha ou tabela, ou qualquer que seja o elemento de “exibição” para processar, e ocupa espaço de acordo. Outros elementos não se movem automaticamente para ocupar esse espaço. O elemento oculto simplesmente não renderiza seus pixels reais para a saída.

“Display: none” por outro lado, na verdade, impede que o elemento seja renderizado completamente . Não ocupa nenhum espaço de layout. Outros elementos que ocupariam algum ou todo o espaço ocupado por este elemento agora se ajustam para ocupar esse espaço, como se o elemento simplesmente não existisse .

“Display” não é apenas mais um atributo visual. Ele estabelece o modo de renderização inteiro do elemento, como se é um bloco, inline, inline-block, tabela, linha de tabela, célula de tabela, item de lista ou o que for! Cada um desses tem ramificações de layout muito diferentes, e não haveria nenhuma maneira razoável de animar ou suavemente transicioná-los (tente imaginar uma transição suave de “block” para “inline” ou vice-versa, por exemplo!).

É por isso que as transições são desativadas se a exibição for alterada (mesmo se a alteração for de ou para “nenhum” – “nenhum” não é meramente invisibilidade, é seu próprio modo de renderização de elemento que significa nenhuma renderização!),

display não é uma das propriedades em que a transição funciona.

Veja http://www.w3.org/TR/css3-transitions/#animatable-properties- para a lista de propriedades que podem ter transições aplicadas a elas.

Eu sei que esta é uma pergunta muito antiga, mas para as pessoas que estão olhando para este segmento, você pode adicionar uma animação personalizada para a propriedade de bloco agora.

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

Demonstração

Nesta demonstração, o submenu muda de display:none para display:block e ainda consegue desaparecer.

De acordo com a display W3C, a display não é uma propriedade animada . Felizmente, a visibility é animadora. Você pode encadear sua transição com uma transição de opacidade ( JSFiddle ):

  • HTML:

     Foo   
  • 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 para teste:

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

Observe que, se você tornar o link transparente, sem definir visibility: hidden , ele permanecerá clicável.

Meu truque de JavaScript é separar o cenário inteiro em duas funções diferentes !

Para preparar as coisas, uma variável global é declarada e um manipulador de events é definido:

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

Então, quando escondendo o elemento, eu uso algo assim:

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

Para reaparecer o elemento, estou fazendo algo assim:

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

Funciona até agora!

Edit: display none não está sendo aplicado neste exemplo.

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

O que está acontecendo acima é que 99% da exibição da animação está definida para bloquear enquanto a opacidade diminui. No último momento, a propriedade de exibição está definida como none.

E o bit mais importante é manter o último quadro depois que a animação termina usando o modo de preenchimento de animação: para frente

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

Aqui estão dois exemplos: https://jsfiddle.net/qwnz9tqg/3/

Eu corri para isso hoje, com uma position: fixed modal position: fixed que eu estava reutilizando. Eu não consegui manter a display: none e, em seguida, animá-lo, como ele simplesmente apareceu, e o z-index (valores negativos, etc) fez coisas estranhas também.

Eu também estava usando uma height: 0 à height: 100% , mas só funcionou quando o modal apareceu. Isto é o mesmo que se você usou para a left: -100% ou algo assim.

Então me ocorreu que havia uma resposta simples. Et voila:

Primeiro, seu modal oculto. Observe que a height é 0 e confira a declaração de height em transições … ela tem 500ms , o que é mais longo do que a minha transição de opacity . Lembre-se, isso afeta a transição de desvanecimento de saída: retornando o modal para seu estado padrão.

 #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; } 

Em segundo lugar, seu modal visível. Digamos que você esteja definindo um .modal-active para o body . Agora a height é 100% e minha transição também mudou. Eu quero que a height seja instantaneamente alterada, e a opacity para levar 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; } 

É isso, funciona como um encanto.

Tomando de algumas destas respostas e algumas sugestões em outros lugares, o seguinte funciona muito bem para menus em foco (estou usando isso com bootstrap 3, especificamente):

 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; } 

Você também pode usar height no lugar de max-height se você especificar os dois valores desde height:auto não é permitido com s de transition . O valor de hover de max-height precisa ser maior que a height do menu.

Alterar overflow:hidden para overflow:visible . Isso funciona melhor. Eu uso assim:

 #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 é melhor porque overflow:hidden age exatamente como um display:none .

Em vez de retornos de chamada, que não existem no CSS, podemos usar transition-delay propriedade de 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; } 

Então, o que está acontecendo aqui?

  1. Quando a class visible é adicionada, a height e a opacity iniciam a animação sem atraso (0ms), embora a height leve 0ms para concluir a animação (equivalente a display: block ) e a opacity leve 600ms.

  2. Quando a class visible é removida, a opacity inicia a animação (atraso de 0 ms, duração de 400 ms) e a altura aguarda 400 ms e só então instantaneamente (0ms) restaura o valor inicial (equivalente a display: none no retorno de chamada de animação).

Note que esta abordagem é melhor do que as que usam visibility . Nesse caso, o elemento ainda ocupa o espaço na página e nem sempre é adequado.

Para mais exemplos, por favor consulte este artigo .

Eu suspeito que alguém apenas começando transições CSS descobre rapidamente que eles não funcionam se você estiver modificando a propriedade de exibição (bloco / nenhum) ao mesmo tempo. Uma alternativa que ainda não foi mencionada é que você pode continuar a usar o display: block / none para ocultar / mostrar o elemento, mas defina sua opacidade para 0, de modo que, mesmo quando for exibido: block, ainda seja invisível. Em seguida, para fade in, adicione outra class CSS, como “on”, que define a opacidade para 1 e define a transição para a opacidade. Como você deve ter imaginado, você precisará usar JavaScript para adicionar essa class “on” ao elemento, mas pelo menos você ainda está usando CSS para a transição real.

PS Se você se encontrar em uma situação onde você precisa fazer tanto display: block, e adicionar class “on”, ao mesmo tempo, adie o último usando setTimeout. Caso contrário, o navegador apenas vê as duas coisas ao mesmo tempo e desativa a transição.

Não é necessário nenhum javascript e não é necessário um tamanho máximo escandalosamente enorme. Em vez disso, defina sua altura máxima em seus elementos de texto e use uma unidade relativa à fonte, como rem ou em. Dessa forma, você pode definir uma altura máxima maior que o seu contêiner, evitando um atraso ou “popping” quando o menu for fechado:

HTML

  

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 } 

Veja um exemplo aqui: http://codepen.io/mindfullsilence/pen/DtzjE

Depois que a resposta aceita de Guillermo foi escrita, a especificação de transição de CSS de 3 de abril de 2012 mudou o comportamento da transição de visibilidade e agora é possível resolver esse problema de maneira mais curta , sem o uso de atraso de transição:

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

O tempo de execução especificado para as duas transições geralmente deve ser idêntico (embora um pouco mais de tempo para visibilidade não seja um problema). Para uma versão em execução, consulte meu blog http://www.taccgl.org/blog/css-transition-visibility.html#visibility-opacity .

Escreve o título da pergunta “Transições no visor: propriedade” e em resposta aos comentários de Rui Marques e josh à resposta aceita: Esta solução funciona nos casos em que é irrelevante se a propriedade de exibição ou visibilidade for usada (como provavelmente foi o caso desta questão). Ele não removerá completamente o elemento como display: none, apenas o tornará invisível, mas ainda permanecerá no stream de documentos e influenciará a posição dos elementos a seguir. Transições que removem completamente o elemento semelhante a exibição: nenhuma pode ser feita usando altura (como indicado por outras respostas e comentários), max-height ou margin-top / bottom, mas também veja Como posso fazer a transição de altura: 0; para height: auto; usando CSS? e meu blog http://www.taccgl.org/blog/css_transition_display.html .

Em resposta ao comentário de GeorgeMillo: Ambas as propriedades e ambas as transições são necessárias: A propriedade opacidade é usada para criar uma animação de fade-in e fade-out e a propriedade de visibilidade para evitar que o elemento ainda reaja nos events do mouse. Transições são necessárias na opacidade do efeito visual e na visibilidade para atrasar a ocultação até que o fade-out seja concluído.

Eu finalmente encontrei uma solução para mim, combinando opacity com position absolute (não ocupar espaço quando oculto).

 .toggle { opacity: 0; position: absolute; transition: opacity 0.8s; } .parent:hover .toggle { opacity: 1; position: static; } 

Eu acho que SalmanPK tem a resposta mais próxima, ele desvanece um item dentro ou fora, com as seguintes animações CSS. No entanto, a propriedade de exibição não anima sem problemas, apenas a opacidade.

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

Se você quiser animar o elemento movendo do bloco de exibição para exibir nenhum, não consigo ver que atualmente é possível apenas com CSS, você tem que obter a altura e usar uma animação CSS para diminuir a altura. Isso é possível com CSS, como mostrado no exemplo abaixo, mas seria complicado saber os valores exatos de altura que você precisa para animar um elemento.

exemplo de 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"; 

Eu me sinto quase mal respondendo a uma pergunta com tantas respostas, mas essa solução tem excelente compatibilidade e eu não a vi ainda:

 .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; } 

Explicação : ele usa o truque visibility: hidden (que é compatível com “show-and-animate” em uma etapa), mas usa a position: absolute; z-index: -1; pointer-events: none; combinação position: absolute; z-index: -1; pointer-events: none; position: absolute; z-index: -1; pointer-events: none; para garantir que o contêiner oculto não ocupe espaço e não responda às interações do usuário .

Eu me deparei com esse problema várias vezes e agora simplesmente fui com:

 .block { opacity: 1; transition: opacity 250ms ease; } .block--invisible { pointer-events: none; opacity: 0; } 

Adicionando o block--invisible class block--invisible todo o Elements não será clicável, mas todos os elementos por trás dele serão por causa do pointer-events:none que é suportado por todos os principais navegadores (sem IE <11).

Em vez de usar o display, você poderia armazenar o elemento ‘fora da canvas’ até que você precisasse, em seguida, definir sua posição para onde você quer e transformá-lo ao mesmo tempo. Isso traz toda uma série de outras questões de design, então, então ymmv. Você provavelmente não desejaria usar a exibição de qualquer maneira, pois você deseja que o conteúdo seja acessível aos leitores de canvas, que na maioria das vezes tentam obedecer a regras de visibilidade – ou seja, se não for visível à vista, ele não aparecerá como conteúdo para o agente.

A solução universal mais simples para o problema é: sinta-se livre para especificar display:none no seu CSS, no entanto você terá que alterá-lo para block (ou qualquer outro) usando JavaScript, e então você também terá que adicionar uma class ao seu elemento em questão que realmente faz a transição com setTimeout () . Isso é tudo.

Ou seja:

  
Well, well, well

Testado nos navegadores mais recentes. Obviamente, não deve funcionar no IE9 ou anterior.

Você pode fazer isso com events de transição, então o que você é, você constrói 2 classs css para a transição, uma segurando a outra animação, mantendo o estado de exibição nenhum. e você as troca depois que a animação termina? No meu caso, eu posso exibir os divs novamente se eu pressionar um btn e remover ambas as classs.

Tente o recortado abaixo …

 $(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")) { //im toggleing and there is already the above class, then what we want it to show the elements , so we remove both classs... 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;} } 
   
Name Age Country
Name Age Country

You can simply use css visibility : hidden/visible instead of display : none/block

 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; } 

you can also use this:

 .dropdown { height: 0px; width: 0px; opacity: .0; color: white; } .dropdown:hover { height: 20px; width: 50px; opacity: 1; transition: opacity 200ms; /* Safari */ -webkit-transition: opacity 200ms; } 

You can get this to work the natural way you expected – using display – but you have to throttle the browser to get it to work, using either JS or as others have suggested a fancy trick with one tag inside another. I don’t care for the inner tag as it further complicates CSS and dimensions, so here’s the JS solution:

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

Starting with a box like:

  

A hidden box. You can have it transition on click with:

 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); 

The CSS is what you’d guess:

 .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); } 

The key is throttling the display property. By removing the hidden class then waiting 50ms, then starting the transition via the added class, we get it to appear and then expand like we wanted, instead of it just blipping onto the screen without any animation. Similar occurs going the other way, except we wait till the animation is over before applying hidden.

Note: I’m abusing .animate(maxWidth) here to avoid setTimeout race conditions. setTimeout is quick to introduce hidden bugs when you or someone else picks up code unaware of it. .animate() can easily be killed with .stop() . I’m just using it to put a 50ms or 2000ms delay on the standard fx queue where it’s easy to find/resolve by other coders building on top of this.

I started an open source skeleton project called Toggle Display Animate

https://marcnewton.github.io/Toggle-Display-Animate/

This skeleton helper will allow you to easily mimic jQuery show/hide but with in/out CSS3 transition animations.

It uses class toggles so you can use any css methods you want on elements besides display:none|block|table|inline etc as well as other alternate uses that can be thought up.

Its main design purpose is for element toggle states, it supports a revert state where hiding the object allows you to run your keyframe in reverse or play an alternate animation for hiding the element.

Most of the markup for the concept I am working on is CSS, there is very little javascript actually used.

There is a demo here: http://marcnewton.co.uk/projects/toggle-display-animate/

It can be handle by using transition timing functions step-end and step-start

For example: https://jsfiddle.net/y72h8Lky/

 $(".run").on("click", function() { $(".popup").addClass("show"); }); $(".popup").on("click", function() { $(".popup").removeClass("show"); }) 
 .popup { opacity: 0; display: block; position: absolute; top: 100%; bottom: 0; left: 0; right: 0; z-index: 1450; background-color: rgba(0, 175, 236, 0.6); transition: opacity 0.3s ease-out, top 0.3s step-end; } .popup.show { transition: opacity 0.3s ease-out, top 0.3s step-start; opacity: 1; top: 0; }