css css3 css-transitions

¿Cómo puedo hacer la transición de altura: 0; a la altura: auto; usando CSS?



transition css (30)

Estoy tratando de hacer un <ul> deslizar hacia abajo usando transiciones CSS.

El <ul> comienza en la height: 0; . Al pasar el mouse, la altura se establece en height:auto; . Sin embargo, esto hace que aparezca simplemente, no una transición,

Si lo hago desde height: 40px; a la height: auto; , luego se deslizará hasta la height: 0; , y luego saltar de repente a la altura correcta.

¿De qué otra manera podría hacer esto sin usar JavaScript?

#child0 { height: 0; overflow: hidden; background-color: #dedede; -moz-transition: height 1s ease; -webkit-transition: height 1s ease; -o-transition: height 1s ease; transition: height 1s ease; } #parent0:hover #child0 { height: auto; } #child40 { height: 40px; overflow: hidden; background-color: #dedede; -moz-transition: height 1s ease; -webkit-transition: height 1s ease; -o-transition: height 1s ease; transition: height 1s ease; } #parent40:hover #child40 { height: auto; } h1 { font-weight: bold; }

The only difference between the two snippets of CSS is one has height: 0, the other height: 40. <hr> <div id="parent0"> <h1>Hover me (height: 0)</h1> <div id="child0">Some content <br>Some content <br>Some content <br>Some content <br>Some content <br>Some content <br> </div> </div> <hr> <div id="parent40"> <h1>Hover me (height: 40)</h1> <div id="child40">Some content <br>Some content <br>Some content <br>Some content <br>Some content <br>Some content <br> </div> </div>


Actualmente no puede animar en altura cuando una de las alturas involucradas es auto , tiene que establecer dos alturas explícitas.


Debes usar escalaY en su lugar.

HTML:

<p>Here (scaleY(1))</p> <ul> <li>Coffee</li> <li>Tea</li> <li>Milk</li> </ul>

CSS:

ul { background-color: #eee; transform: scaleY(0); transform-origin: top; transition: transform 0.26s ease; } p:hover ~ ul { transform: scaleY(1); }

He creado una versión prefijada del proveedor del código anterior en jsfiddle, http://jsfiddle.net/dotnetCarpenter/PhyQc/9/ y cambié su jsfiddle para usar scaleY en lugar de height, http://jsfiddle.net/dotnetCarpenter/7cnfc/206/ .


La solución que siempre he usado fue primero desvanecerse, luego reducir el font-size , el padding y los valores de margin . No parece lo mismo que una toallita, pero funciona sin una height estática o una height max-height .

Ejemplo de trabajo:

/* final display */ #menu #list { margin: .5em 1em; padding: 1em; } /* hide */ #menu:not(:hover) #list { font-size: 0; margin: 0; opacity: 0; padding: 0; /* fade out, then shrink */ transition: opacity .25s, font-size .5s .25s, margin .5s .25s, padding .5s .25s; } /* reveal */ #menu:hover #list { /* unshrink, then fade in */ transition: font-size .25s, margin .25s, padding .25s, opacity .5s .25s; }

<div id="menu"> <b>hover me</b> <ul id="list"> <li>item</li> <li>item</li> <li>item</li> <li>item</li> <li>item</li> </ul> </div> <p>Another paragraph...</p>


Mi solución es hacer una transición de max-height a la altura exacta del contenido para obtener una animación suave y agradable, luego usar una retrollamada de transición y fin para establecer la altura máxima en 9999px para que el contenido pueda cambiar de tamaño libremente.

var content = $(''#content''); content.inner = $(''#content .inner''); // inner div needed to get size of content when closed // css transition callback content.on(''transitionEnd webkitTransitionEnd transitionend oTransitionEnd msTransitionEnd'', function(e){ if(content.hasClass(''open'')){ content.css(''max-height'', 9999); // try setting this to ''none''... I dare you! } }); $(''#toggle'').on(''click'', function(e){ content.toggleClass(''open closed''); content.contentHeight = content.outerHeight(); if(content.hasClass(''closed'')){ // disable transitions & set max-height to content height content.removeClass(''transitions'').css(''max-height'', content.contentHeight); setTimeout(function(){ // enable & start transition content.addClass(''transitions'').css({ ''max-height'': 0, ''opacity'': 0 }); }, 10); // 10ms timeout is the secret ingredient for disabling/enabling transitions // chrome only needs 1ms but FF needs ~10ms or it chokes on the first animation for some reason }else if(content.hasClass(''open'')){ content.contentHeight += content.inner.outerHeight(); // if closed, add inner height to content height content.css({ ''max-height'': content.contentHeight, ''opacity'': 1 }); } });

.transitions { transition: all 0.5s ease-in-out; -webkit-transition: all 0.5s ease-in-out; -moz-transition: all 0.5s ease-in-out; } body { font-family:Arial; line-height: 3ex; } code { display: inline-block; background: #fafafa; padding: 0 1ex; } #toggle { display:block; padding:10px; margin:10px auto; text-align:center; width:30ex; } #content { overflow:hidden; margin:10px; border:1px solid #666; background:#efefef; opacity:1; } #content .inner { padding:10px; overflow:auto; }

<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script> <div id="content" class="open"> <div class="inner"> <h3>Smooth CSS Transitions Between <code>height: 0</code> and <code>height: auto</code></h3> <p>A clever workaround is to use <code>max-height</code> instead of <code>height</code>, and set it to something bigger than your content. Problem is the browser uses this value to calculate transition duration. So if you set it to <code>max-height: 1000px</code> but the content is only 100px high, the animation will be 10x too fast.</p> <p>Another option is to measure the content height with JS and transition to that fixed value, but then you have to keep track of the content and manually resize it if it changes.</p> <p>This solution is a hybrid of the two - transition to the measured content height, then set it to <code>max-height: 9999px</code> after the transition for fluid content sizing.</p> </div> </div> <br /> <button id="toggle">Challenge Accepted!</button>


Sé que esta es la respuesta número treinta a esta pregunta, pero creo que vale la pena, así que aquí va. Esta es una solución solo para CSS con las siguientes propiedades:

  • No hay demora al principio, y la transición no se detiene antes. En ambas direcciones (expandiéndose y colapsando), si especifica una duración de transición de 300 ms en su CSS, entonces la transición toma 300 ms, punto.
  • Está haciendo la transición a la altura real (a diferencia de transform: scaleY(0) ), por lo que hace lo correcto si hay contenido después del elemento plegable.
  • Si bien (como en otras soluciones) hay números mágicos (como "elegir una longitud que sea más alta de lo que será tu caja"), no es fatal si tu suposición termina siendo errónea. La transición puede no parecer sorprendente en ese caso, pero antes y después de la transición, esto no es un problema: en el estado expandido ( height: auto ), todo el contenido siempre tiene la altura correcta (a diferencia de, por ejemplo, si elige un max-height que resulta ser demasiado baja). Y en el estado colapsado, la altura es cero como debería.

Manifestación

Aquí hay una demostración con tres elementos plegables, todos de diferentes alturas, que usan el mismo CSS. Es posible que desee hacer clic en "página completa" después de hacer clic en "ejecutar fragmento de código". Tenga en cuenta que el JavaScript solo alterna la clase CSS collapsed , no hay medidas involucradas. (Puede hacer esta demostración exacta sin ningún tipo de JavaScript utilizando una casilla de verificación o :target ). También tenga en cuenta que la parte del CSS que es responsable de la transición es bastante corta, y el HTML solo requiere un elemento envoltorio adicional.

$(function () { $(".toggler").click(function () { $(this).next().toggleClass("collapsed"); $(this).toggleClass("toggled"); // this just rotates the expander arrow }); });

.collapsible-wrapper { display: flex; overflow: hidden; } .collapsible-wrapper:after { content: ''''; height: 50px; transition: height 0.3s linear, max-height 0s 0.3s linear; max-height: 0px; } .collapsible { transition: margin-bottom 0.3s cubic-bezier(0, 0, 0, 1); margin-bottom: 0; max-height: 1000000px; } .collapsible-wrapper.collapsed > .collapsible { margin-bottom: -2000px; transition: margin-bottom 0.3s cubic-bezier(1, 0, 1, 1), visibility 0s 0.3s, max-height 0s 0.3s; visibility: hidden; max-height: 0; } .collapsible-wrapper.collapsed:after { height: 0; transition: height 0.3s linear; max-height: 50px; } /* END of the collapsible implementation; the stuff below is just styling for this demo */ #container { display: flex; align-items: flex-start; max-width: 1000px; margin: 0 auto; } .menu { border: 1px solid #ccc; box-shadow: 0 1px 3px rgba(0,0,0,0.5); margin: 20px; } .menu-item { display: block; background: linear-gradient(to bottom, #fff 0%,#eee 100%); margin: 0; padding: 1em; line-height: 1.3; } .collapsible .menu-item { border-left: 2px solid #888; border-right: 2px solid #888; background: linear-gradient(to bottom, #eee 0%,#ddd 100%); } .menu-item.toggler { background: linear-gradient(to bottom, #aaa 0%,#888 100%); color: white; cursor: pointer; } .menu-item.toggler:before { content: ''''; display: block; border-left: 8px solid white; border-top: 8px solid transparent; border-bottom: 8px solid transparent; width: 0; height: 0; float: right; transition: transform 0.3s ease-out; } .menu-item.toggler.toggled:before { transform: rotate(90deg); } body { font-family: sans-serif; font-size: 14px; } *, *:after { box-sizing: border-box; }

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <div id="container"> <div class="menu"> <div class="menu-item">Something involving a holodeck</div> <div class="menu-item">Send an away team</div> <div class="menu-item toggler">Advanced solutions</div> <div class="collapsible-wrapper collapsed"> <div class="collapsible"> <div class="menu-item">Separate saucer</div> <div class="menu-item">Send an away team that includes the captain (despite Riker''s protest)</div> <div class="menu-item">Ask Worf</div> <div class="menu-item">Something involving Wesley, the 19th century, and a holodeck</div> <div class="menu-item">Ask Q for help</div> </div> </div> <div class="menu-item">Sweet-talk the alien aggressor</div> <div class="menu-item">Re-route power from auxiliary systems</div> </div> <div class="menu"> <div class="menu-item">Something involving a holodeck</div> <div class="menu-item">Send an away team</div> <div class="menu-item toggler">Advanced solutions</div> <div class="collapsible-wrapper collapsed"> <div class="collapsible"> <div class="menu-item">Separate saucer</div> <div class="menu-item">Send an away team that includes the captain (despite Riker''s protest)</div> </div> </div> <div class="menu-item">Sweet-talk the alien aggressor</div> <div class="menu-item">Re-route power from auxiliary systems</div> </div> <div class="menu"> <div class="menu-item">Something involving a holodeck</div> <div class="menu-item">Send an away team</div> <div class="menu-item toggler">Advanced solutions</div> <div class="collapsible-wrapper collapsed"> <div class="collapsible"> <div class="menu-item">Separate saucer</div> <div class="menu-item">Send an away team that includes the captain (despite Riker''s protest)</div> <div class="menu-item">Ask Worf</div> <div class="menu-item">Something involving Wesley, the 19th century, and a holodeck</div> <div class="menu-item">Ask Q for help</div> <div class="menu-item">Separate saucer</div> <div class="menu-item">Send an away team that includes the captain (despite Riker''s protest)</div> <div class="menu-item">Ask Worf</div> <div class="menu-item">Something involving Wesley, the 19th century, and a holodeck</div> <div class="menu-item">Ask Q for help</div> </div> </div> <div class="menu-item">Sweet-talk the alien aggressor</div> <div class="menu-item">Re-route power from auxiliary systems</div> </div> </div>

¿Como funciona?

De hecho, hay dos transiciones involucradas en hacer que esto suceda. Uno de ellos hace la transición del margin-bottom de 0px (en el estado expandido) a -2000px en el estado colapsado (similar a esta respuesta ). El 2000 aquí es el primer número mágico, se basa en la suposición de que su caja no será más alta que esto (2000 píxeles parece una opción razonable).

Usar la transición del margin-bottom solo por sí mismo tiene dos problemas:

  • Si realmente tiene un cuadro que es más alto que 2000 píxeles, entonces un margin-bottom: -2000px no ocultará todo, habrá cosas visibles incluso en el caso colapsado. Esta es una solución menor que haremos más tarde.
  • Si el cuadro real tiene, digamos, 1000 píxeles de alto, y su transición tiene una longitud de 300 ms, entonces la transición visible ya habrá terminado después de unos 150 ms (o, en la dirección opuesta, comienza 150 ms tarde).

Arreglar este segundo problema es donde entra la segunda transición, y esta transición se orienta conceptualmente a la altura mínima de la envoltura ("conceptualmente" porque en realidad no estamos usando la propiedad min-height para esto; más información más adelante).

Aquí hay una animación que muestra cómo combinar la transición del margen inferior con la transición de altura mínima, ambas de igual duración, nos da una transición combinada de altura completa a altura cero que tiene la misma duración.

La barra izquierda muestra cómo el margen inferior negativo empuja la parte inferior hacia arriba, reduciendo la altura visible. La barra central muestra cómo la altura mínima garantiza que, en el caso de colapso, la transición no finalice antes, y en el caso de expansión, la transición no comience tarde. La barra derecha muestra cómo la combinación de los dos hace que el cuadro pase de la altura máxima a la altura cero en la cantidad de tiempo correcta.

Para mi demostración, me he decidido por 50px como el valor de altura mínima superior. Este es el segundo número mágico, y debería ser más bajo que la altura de la caja. 50px parece razonable también; Parece poco probable que muy a menudo quieras hacer un elemento plegable que no tenga ni siquiera 50 píxeles de alto en primer lugar.

Como puede ver en la animación, la transición resultante es continua, pero no es diferenciable: en el momento en que la altura mínima es igual a la altura total ajustada por el margen inferior, hay un cambio repentino en la velocidad. Esto es muy notable en la animación porque utiliza una función de temporización lineal para ambas transiciones, y porque toda la transición es muy lenta. En el caso real (mi demostración en la parte superior), la transición solo toma 300 ms, y la transición del margen inferior no es lineal. He jugado con muchas funciones de tiempo diferentes para ambas transiciones, y las que terminé sentí que funcionaron mejor para la mayor variedad de casos.

Quedan dos problemas por arreglar:

  1. el punto desde arriba, donde los cuadros de más de 2000 píxeles de altura no están completamente ocultos en el estado colapsado,
  2. y el problema inverso, donde en el caso no oculto, los cuadros de menos de 50 píxeles de altura son demasiado altos incluso cuando la transición no se está ejecutando, porque la altura mínima los mantiene en 50 píxeles.

Resolvemos el primer problema al darle al elemento contenedor una max-height: 0 en el caso colapsado, con una transición de 0s 0.3s . Esto significa que no es realmente una transición, pero la max-height se aplica con un retraso; solo se aplica una vez que la transición ha terminado. Para que esto funcione correctamente, también debemos elegir una max-height numérica para el estado opuesto, no colapsado. Pero a diferencia del caso de 2000px, donde la selección de un número demasiado grande afecta la calidad de la transición, en este caso, realmente no importa. Así que solo podemos elegir un número que sea tan alto que sepamos que ninguna altura se acercará a esto. Escogí un millón de píxeles. Si crees que es posible que debas admitir contenido de una altura de más de un millón de píxeles, entonces 1) Lo siento, y 2) solo agrega un par de ceros.

El segundo problema es la razón por la que no estamos usando min-height mínima para la transición de altura mínima. En su lugar, hay un ::after pseudo-elemento en el contenedor con una height que transita de 50px a cero. Esto tiene el mismo efecto que una min-height : no permitirá que el contenedor se contraiga por debajo de la altura que tenga el pseudo-elemento actualmente. Pero como estamos usando la height , no min-height , ahora podemos usar max-height (una vez que se aplique con un retraso) para establecer la altura real del pseudo-elemento una vez que la transición haya terminado, asegurando que al menos fuera de la Transición, incluso los elementos pequeños tienen la altura correcta. Debido min-height es stronger que max-height , esto no funcionaría si utilizáramos la min-height del contenedor en lugar de la min-height del pseudo-elemento. Al igual que la max-height en el párrafo anterior, esta max-height también necesita un valor para el extremo opuesto de la transición. Pero en este caso solo podemos elegir los 50px.

Probado en Chrome (Win, Mac, Android, iOS), Firefox (Win, Mac, Android), Edge, IE11 (excepto por un problema de diseño de flexbox con mi demo que no me molesté en la depuración) y Safari (Mac, iOS) ). Hablando de flexbox, debería ser posible hacer este trabajo sin utilizar ningún flexbox; de hecho, creo que podría hacer que casi todo funcione en IE7, excepto por el hecho de que no tendrá transiciones CSS, lo que lo convierte en un ejercicio bastante inútil.


Una solución visual para animar la altura utilizando transiciones CSS3 es animar el relleno en su lugar.

No consigues el efecto de borrado completo, pero jugar con la duración de la transición y los valores de relleno debería acercarte lo suficiente. Si no desea establecer explícitamente la altura / altura máxima, esto debería ser lo que está buscando.

div { height: 0; overflow: hidden; padding: 0 18px; -webkit-transition: all .5s ease; -moz-transition: all .5s ease; transition: all .5s ease; } div.animated { height: auto; padding: 24px 18px; }

http://jsfiddle.net/catharsis/n5XfG/17/ (eliminó el jsFiddle del stephband anterior)


Use max-height en la transformación y no la height . Y establezca un valor en max-height en algo más grande de lo que su caja jamás obtendrá.

Vea la demostración de JSFiddle proporcionada por Chris Jordan en otra answer aquí.

#menu #list { max-height: 0; transition: max-height 0.15s ease-out; overflow: hidden; background: #d5d5d5; } #menu:hover #list { max-height: 500px; transition: max-height 0.25s ease-in; }

<div id="menu"> <a>hover me</a> <ul id="list"> <!-- Create a bunch, or not a bunch, of li''s to see the timing. --> <li>item</li> <li>item</li> <li>item</li> <li>item</li> <li>item</li> </ul> </div>


Usted puede, con un poco de jiggery-pokery no semántico. Mi enfoque habitual es animar la altura de un DIV exterior que tiene un solo hijo que es un DIV sin estilo utilizado solo para medir la altura del contenido.

function growDiv() { var growDiv = document.getElementById(''grow''); if (growDiv.clientHeight) { growDiv.style.height = 0; } else { var wrapper = document.querySelector(''.measuringWrapper''); growDiv.style.height = wrapper.clientHeight + "px"; } }

#grow { -moz-transition: height .5s; -ms-transition: height .5s; -o-transition: height .5s; -webkit-transition: height .5s; transition: height .5s; height: 0; overflow: hidden; outline: 1px solid red; }

<input type="button" onclick="growDiv()" value="grow"> <div id=''grow''> <div class=''measuringWrapper''> <div> The contents of my div. </div> <div> The contents of my div. </div> <div> The contents of my div. </div> <div> The contents of my div. </div> <div> The contents of my div. </div> <div> The contents of my div. </div> </div> </div>

A uno solo le gustaría poder prescindir del .measuringWrapper y simplemente configurar la altura del DIV en automático y tener esa animación, pero eso no parece funcionar (la altura se establece, pero no ocurre ninguna animación).

function growDiv() { var growDiv = document.getElementById(''grow''); if (growDiv.clientHeight) { growDiv.style.height = 0; } else { growDiv.style.height = ''auto''; } }

#grow { -moz-transition: height .5s; -ms-transition: height .5s; -o-transition: height .5s; -webkit-transition: height .5s; transition: height .5s; height: 0; overflow: hidden; outline: 1px solid red; }

<input type="button" onclick="growDiv()" value="grow"> <div id=''grow''> <div> The contents of my div. </div> <div> The contents of my div. </div> <div> The contents of my div. </div> <div> The contents of my div. </div> <div> The contents of my div. </div> <div> The contents of my div. </div> </div>

Mi interpretación es que se necesita una altura explícita para que se ejecute la animación. No puede obtener una animación en altura cuando la altura (la altura inicial o final) es auto .


Creo que se me ocurrió una solución muy sólida.

¡DE ACUERDO!Sé que este problema es tan antiguo como Internet, pero creo que tengo una solución que convertí en un complemento llamado transición mutante . Mi solución establece los style=""atributos para los elementos rastreados cada vez que hay un cambio en el DOM. El resultado final es que puede usar un buen CSS de ole para sus transiciones y no usar arreglos piratas o javascript especial. Lo único que tiene que hacer es configurar lo que desea rastrear en el elemento en cuestión usando data-mutant-attributes="X".

<div data-mutant-attributes="height"> This is an example with mutant-transition </div>

¡Eso es! Esta solución utiliza MutationObserver para seguir los cambios en el DOM. Debido a esto, realmente no tienes que configurar nada o usar javascript para animar manualmente las cosas. Los cambios son seguidos automáticamente. Sin embargo, debido a que usa MutationObserver, esto solo hará la transición en IE11 +.

Violines


Solución Flexbox

Pros:

  • sencillo
  • no JS
  • transición suave

Contras:

  • El elemento debe colocarse en un contenedor flexible de altura fija.

La forma en que funciona es teniendo siempre una base flexible: auto en el elemento con contenido, y haciendo la transición flex-grow y flex-shrink en su lugar.

Edición: JS Fiddle mejorado inspirado en la interfaz de Xbox One.

* { margin: 0; padding: 0; box-sizing: border-box; transition: 0.25s; font-family: monospace; } body { margin: 10px 0 0 10px; } .box { width: 150px; height: 150px; margin: 0 2px 10px 0; background: #2d333b; border: solid 10px #20262e; overflow: hidden; display: inline-flex; flex-direction: column; } .space { flex-basis: 100%; flex-grow: 1; flex-shrink: 0; } p { flex-basis: auto; flex-grow: 0; flex-shrink: 1; background: #20262e; padding: 10px; width: 100%; text-align: left; color: white; } .box:hover .space { flex-grow: 0; flex-shrink: 1; } .box:hover p { flex-grow: 1; flex-shrink: 0; }

<div class="box"> <div class="space"></div> <p> Super Metroid Prime Fusion </p> </div> <div class="box"> <div class="space"></div> <p> Resident Evil 2 Remake </p> </div> <div class="box"> <div class="space"></div> <p> Yolo The Game </p> </div> <div class="box"> <div class="space"></div> <p> Final Fantasy 7 Remake + All Additional DLC + Golden Tophat </p> </div> <div class="box"> <div class="space"></div> <p> DerpVille </p> </div>

JS Fiddle


Al expandirse en la respuesta de @jake, la transición se extenderá hasta el valor de altura máxima, lo que provocará una animación extremadamente rápida; si configura las transiciones para ambos: desplazar y apagar puede controlar la velocidad de locos un poco más.

Por lo tanto, li: hover es cuando el mouse ingresa al estado y luego la transición en la propiedad no activada será la salida del mouse.

Esperemos que esto sea de alguna ayuda.

p.ej:

.sidemenu li ul { max-height: 0px; -webkit-transition: all .3s ease; -moz-transition: all .3s ease; -o-transition: all .3s ease; -ms-transition: all .3s ease; transition: all .3s ease; } .sidemenu li:hover ul { max-height: 500px; -webkit-transition: all 1s ease; -moz-transition: all 1s ease; -o-transition: all 1s ease; -ms-transition: all 1s ease; transition: all 1s ease; } /* Adjust speeds to the possible height of the list */

Aquí hay un violín: http://jsfiddle.net/BukwJ/


Establezca la altura en automático y cambie la altura máxima.

Probado en Chrome v17

div { position: absolute; width:100%; bottom:0px; left:0px; background:#333; color: #FFF; max-height:100%; /**/ height:auto; /**/ -webkit-transition: all 0.2s ease-in-out; -moz-transition: all 0.2s ease-in-out; -o-transition: all 0.2s ease-in-out; -ms-transition: all 0.2s ease-in-out; transition: all 0.2s ease-in-out; } .close { max-height:0%; /**/ }


Este es un problema regular que he resuelto asi

http://jsfiddle.net/ipeshev/d1dfr0jz/

Intente establecer el retraso del estado cerrado en algún número negativo y juegue un poco con el valor. Verá la diferencia. Se puede hacer casi para mentir el ojo humano;).

Funciona en los principales navegadores, pero lo suficientemente bueno para mí. Es extraño pero da algunos resultados.

.expandable { max-height: 0px; overflow: hidden; transition: all 1s linear -0.8s; } button:hover ~ .expandable { max-height: 9000px; transition: all 1s ease-in-out; }


La respuesta de Jake para animar la altura máxima es genial, pero encontré que la demora causada por el ajuste de una altura máxima grande es molesta.

Uno podría mover el contenido plegable a una división interna y calcular la altura máxima obteniendo la altura de la división interna (a través de JQuery sería la Altura exterior ()).

$(''button'').bind(''click'', function(e) { e.preventDefault(); w = $(''#outer''); if (w.hasClass(''collapsed'')) { w.css({ "max-height": $(''#inner'').outerHeight() + ''px'' }); } else { w.css({ "max-height": "0px" }); } w.toggleClass(''collapsed''); });

Aquí hay un enlace jsfiddle: http://jsfiddle.net/pbatey/duZpT

Aquí hay un jsfiddle con la cantidad mínima absoluta de código requerida: http://jsfiddle.net/8ncjjxh8/


Me doy cuenta de que este hilo está envejeciendo, pero ocupa un lugar destacado en ciertas búsquedas de Google, así que creo que vale la pena actualizarlo.

También acaba de obtener / establecer la propia altura del elemento:

var load_height = document.getElementById(''target_box'').clientHeight; document.getElementById(''target_box'').style.height = load_height + ''px'';

Debería volcar este Javascript inmediatamente después de la etiqueta de cierre de target_box en una etiqueta de script en línea.


No hay valores codificados.

No JavaScript.

No hay aproximaciones.

El truco es usar un oculto y duplicado divpara que el navegador entienda lo que significa el 100%.

Este método es adecuado siempre que pueda duplicar el DOM del elemento que desea animar.

.outer { border: dashed red 1px; position: relative; } .dummy { visibility: hidden; } .real { position: absolute; background: yellow; height: 0; transition: height 0.5s; overflow: hidden; } .outer:hover>.real { height: 100%; }

Hover over the box below: <div class="outer"> <!-- The actual element that you''d like to animate --> <div class="real"> unpredictable content unpredictable content unpredictable content unpredictable content unpredictable content unpredictable content unpredictable content unpredictable content unpredictable content unpredictable content unpredictable content unpredictable content unpredictable content unpredictable content unpredictable content </div> <!-- An exact copy of the element you''d like to animate. --> <div class="dummy" aria-hidden="true"> unpredictable content unpredictable content unpredictable content unpredictable content unpredictable content unpredictable content unpredictable content unpredictable content unpredictable content unpredictable content unpredictable content unpredictable content unpredictable content unpredictable content unpredictable content </div> </div>


No he leído todo en detalle, pero he tenido este problema recientemente e hice lo siguiente:

div.class{ min-height:1%; max-height:200px; -webkit-transition: all 0.5s ease; -moz-transition: all 0.5s ease; -o-transition: all 0.5s ease; -webkit-transition: all 0.5s ease; transition: all 0.5s ease; overflow:hidden; } div.class:hover{ min-height:100%; max-height:3000px; }

Esto le permite tener un div que al principio muestra contenido de hasta 200px de altura y al pasar el tamaño, su tamaño se vuelve al menos tan alto como todo el contenido del div. La Div no se convierte en 3000px pero 3000px es el límite que estoy imponiendo. Asegúrese de tener la transición en el modo no: desplazarse, de lo contrario podría obtener una representación extraña. De esta manera, el hover hereda del no: hover.

La transición no funciona desde px a% o a auto. Necesitas usar la misma unidad de medida. Esto funciona bien para mi. Usar HTML5 lo hace perfecto ...

Recuerda que siempre hay un trabajo alrededor ...; )

Espero que alguien encuentre esto útil


Puede realizar la transición desde altura: 0 a altura: automático siempre que también proporcione min-height y max-height.

div.stretchy{ transition: 1s linear; } div.stretchy.hidden{ height: 0; } div.stretchy.visible{ height: auto; min-height:40px; max-height:400px; }


Aquí hay una manera de pasar de cualquier altura de inicio, incluido 0, a auto (tamaño completo y flexible) sin requerir un código de configuración permanente por nodo o cualquier código de usuario para inicializar: https://github.com/csuwildcat/transition-auto . Este es básicamente el santo grial para lo que quieres, creo -> http://codepen.io/csuwldcat/pen/kwsdF . Simplemente coloque el siguiente archivo JS en su página, y todo lo que debe hacer después de eso es agregar / eliminar un único atributo booleano reveal=""- desde los nodos que desea expandir y contraer.

Aquí tiene todo lo que necesita hacer como usuario, una vez que incluya el bloque de código que se encuentra debajo del código de ejemplo:

/*** Nothing out of the ordinary in your styles ***/ <style> div { height: 0; overflow: hidden; transition: height 1s; } </style> /*** Just add and remove one attribute and transition to/from auto! ***/ <div> I have tons of content and I am 0px in height you can''t see me... </div> <div reveal> I have tons of content and I am 0px in height you can''t see me... but now that you added the ''reveal'' attribute, I magically transitioned to full height!... </div>

Aquí está el bloque de código para incluir en su página, después de eso, todo es salsa:

Coloque este archivo JS en su página: todo funciona Just Works ™

/ * Código de altura: auto; transición * /

(function(doc){ /* feature detection for browsers that report different values for scrollHeight when an element''s overflow is hidden vs visible (Firefox, IE) */ var test = doc.documentElement.appendChild(doc.createElement(''x-reveal-test'')); test.innerHTML = ''-''; test.style.cssText = ''display: block !important; height: 0px !important; padding: 0px !important; font-size: 0px !important; border-width: 0px !important; line-height: 1px !important; overflow: hidden !important;''; var scroll = test.scrollHeight || 2; doc.documentElement.removeChild(test); var loading = true, numReg = /^([0-9]*/.?[0-9]*)(.*)/, skipFrame = function(fn){ requestAnimationFrame(function(){ requestAnimationFrame(fn); }); }, /* 2 out of 3 uses of this function are purely to work around Chrome''s catastrophically busted implementation of auto value CSS transitioning */ revealFrame = function(el, state, height){ el.setAttribute(''reveal-transition'', ''frame''); el.style.height = height; skipFrame(function(){ el.setAttribute(''reveal-transition'', state); el.style.height = ''''; }); }, transitionend = function(e){ var node = e.target; if (node.hasAttribute(''reveal'')) { if (node.getAttribute(''reveal-transition'') == ''running'') revealFrame(node, ''complete'', ''''); } else { node.removeAttribute(''reveal-transition''); node.style.height = ''''; } }, animationstart = function(e){ var node = e.target, name = e.animationName; if (name == ''reveal'' || name == ''unreveal'') { if (loading) return revealFrame(node, ''complete'', ''auto''); var style = getComputedStyle(node), offset = (Number(style.paddingTop.match(numReg)[1])) + (Number(style.paddingBottom.match(numReg)[1])) + (Number(style.borderTopWidth.match(numReg)[1])) + (Number(style.borderBottomWidth.match(numReg)[1])); if (name == ''reveal''){ node.setAttribute(''reveal-transition'', ''running''); node.style.height = node.scrollHeight - (offset / scroll) + ''px''; } else { if (node.getAttribute(''reveal-transition'') == ''running'') node.style.height = ''''; else revealFrame(node, ''running'', node.scrollHeight - offset + ''px''); } } }; doc.addEventListener(''animationstart'', animationstart, false); doc.addEventListener(''MSAnimationStart'', animationstart, false); doc.addEventListener(''webkitAnimationStart'', animationstart, false); doc.addEventListener(''transitionend'', transitionend, false); doc.addEventListener(''MSTransitionEnd'', transitionend, false); doc.addEventListener(''webkitTransitionEnd'', transitionend, false); /* Batshit readyState/DOMContentLoaded code to dance around Webkit/Chrome animation auto-run weirdness on initial page load. If they fixed their code, you could just check for if(doc.readyState != ''complete'') in animationstart''s if(loading) check */ if (document.readyState == ''complete'') { skipFrame(function(){ loading = false; }); } else document.addEventListener(''DOMContentLoaded'', function(e){ skipFrame(function(){ loading = false; }); }, false); /* Styles that allow for ''reveal'' attribute triggers */ var styles = doc.createElement(''style''), t = ''transition: none; '', au = ''animation: reveal 0.001s; '', ar = ''animation: unreveal 0.001s; '', clip = '' { from { opacity: 0; } to { opacity: 1; } }'', r = ''keyframes reveal'' + clip, u = ''keyframes unreveal'' + clip; styles.textContent = ''[reveal] { -ms-''+ au + ''-webkit-''+ au +''-moz-''+ au + au +''}'' + ''[reveal-transition="frame"] { -ms-'' + t + ''-webkit-'' + t + ''-moz-'' + t + t + ''height: auto; }'' + ''[reveal-transition="complete"] { height: auto; }'' + ''[reveal-transition]:not([reveal]) { -webkit-''+ ar +''-moz-''+ ar + ar +''}'' + ''@-ms-'' + r + ''@-webkit-'' + r + ''@-moz-'' + r + r + ''@-ms-'' + u +''@-webkit-'' + u + ''@-moz-'' + u + u; doc.querySelector(''head'').appendChild(styles); })(document);

/ * Código para DEMO * /

document.addEventListener(''click'', function(e){ if (e.target.nodeName == ''BUTTON'') { var next = e.target.nextElementSibling; next.hasAttribute(''reveal'') ? next.removeAttribute(''reveal'') : next.setAttribute(''reveal'', ''''); } }, false);


Aquí hay una solución que acabo de usar en combinación con jQuery. Esto funciona para la siguiente estructura HTML:

<nav id="main-nav"> <ul> <li> <a class="main-link" href="yourlink.html">Link</a> <ul> <li><a href="yourlink.html">Sub Link</a></li> </ul> </li> </ul> </nav>

y la función:

$(''#main-nav li ul'').each(function(){ $me = $(this); //Count the number of li elements in this UL var liCount = $me.find(''li'').size(), //Multiply the liCount by the height + the margin on each li ulHeight = liCount * 28; //Store height in the data-height attribute in the UL $me.attr("data-height", ulHeight); });

A continuación, puede utilizar una función de clic para establecer y eliminar la altura utilizando css()

$(''#main-nav li a.main-link'').click(function(){ //Collapse all submenus back to 0 $(''#main-nav li ul'').removeAttr(''style''); $(this).parent().addClass(''current''); //Set height on current submenu to it''s height var $currentUl = $(''li.current ul''), currentUlHeight = $currentUl.attr(''data-height''); })

CSS:

#main-nav li ul { height: 0; position: relative; overflow: hidden; opacity: 0; filter: alpha(opacity=0); -ms-filter: "alpha(opacity=0)"; -khtml-opacity: 0; -moz-opacity: 0; -webkit-transition: all .6s ease-in-out; -moz-transition: all .6s ease-in-out; -o-transition: all .6s ease-in-out; -ms-transition: all .6s ease-in-out; transition: all .6s ease-in-out; } #main-nav li.current ul { opacity: 1.0; filter: alpha(opacity=100); -ms-filter: "alpha(opacity=100)"; -khtml-opacity: 1.0; -moz-opacity: 1.0; } .ie #main-nav li.current ul { height: auto !important } #main-nav li { height: 25px; display: block; margin-bottom: 3px }


EDITAR: Desplácese hacia abajo para obtener una respuesta actualizada.
Estaba haciendo una lista desplegable y vi este Post ... muchas respuestas diferentes, pero también decido compartir mi lista desplegable, ... No es perfecto, pero al menos usará solo css para ¡desplegable! He estado usando transform: translateY (y) para transformar la lista a la vista ...
Puedes ver más en la prueba
http://jsfiddle.net/BVEpc/4/
He colocado div detrás de cada li porque mi la lista desplegable viene de arriba y para mostrarlos correctamente, esto era necesario, mi código div es:

#menu div { transition: 0.5s 1s; z-index:-1; -webkit-transform:translateY(-100%); -webkit-transform-origin: top; }

y flotar es:

#menu > li:hover div { transition: 0.5s; -webkit-transform:translateY(0); }

y como ul height está configurada para el contenido que puede superar tu contenido corporal, por eso hice esto para ul:

#menu ul { transition: 0s 1.5s; visibility:hidden; overflow:hidden; }

y flotar:

#menu > li:hover ul { transition:none; visibility:visible; }

la segunda vez después de la transición es una demora y se ocultará después de que mi lista desplegable se haya cerrado animadamente ...
Espero que luego alguien se beneficie de esta.

EDIT: ¡No puedo creer que la gente realmente use este prototipo! este menú desplegable es solo para un submenú y eso es todo !! He actualizado uno mejor que puede tener dos submenús para ambas direcciones ltr y rtl con soporte de IE 8.
Fiddle for LTR
Fiddle for RTL
espero que alguien encuentre esto útil en el futuro.


Esto no es exactamente una "solución" al problema, sino más bien una solución. Solo funciona como está escrito con texto, pero puedo cambiarlo para que funcione con otros elementos según sea necesario, estoy seguro.

.originalContent { font-size:0px; transition:font-size .2s ease-in-out; } .show { /* class to add to content */ font-size:14px; }

Aquí hay un ejemplo: http://codepen.io/overthemike/pen/wzjRKa

Esencialmente, establece el tamaño de fuente en 0 y la transición que en lugar de la altura, o la altura máxima, o escalaY () etc. a un ritmo lo suficientemente rápido como para que la altura se transforme en lo que desea. Actualmente, no es posible transformar la altura real con CSS a auto, pero sí es posible transformar el contenido dentro, por lo tanto, la transición del tamaño de fuente.

  • Nota: hay código JavaScript en el codepen, pero su único propósito es agregar / eliminar clases de css al hacer clic para el acordeón. Esto se puede hacer con botones de radio ocultos, pero no estaba enfocado en eso, solo en la transformación de altura.

Hubo poca mención de la Element.scrollHeightpropiedad que puede ser útil aquí y aún se puede usar con una transición CSS pura. La propiedad siempre contiene la altura "completa" de un elemento, independientemente de si su contenido se desborda y cómo se desborda como resultado de la altura colapsada (por ejemplo height: 0).

Como tal, para un elemento height: 0(efectivamente colapsado completamente), su altura "normal" o "completa" todavía está disponible a través de su scrollHeightvalor (invariablemente una longitud de píxel ).

Para tal elemento, suponiendo que ya tiene configurada la transición como, por ejemplo, (utilizando la ulpregunta original):

ul { height: 0; transition: height 1s; /* An example transition. */ }

Podemos activar la "expansión" animada deseada de la altura, usando solo CSS, con algo como lo siguiente (aquí, asumiendo que la ulvariable se refiere a la lista):

ul.style.height = ul.scrollHeight + "px";

Eso es. Si necesita colapsar la lista, una de las dos siguientes declaraciones lo hará:

ul.style.height = "0"; ul.style.removeProperty("height");

Mi caso de uso particular giraba en torno a listas animadas de longitudes desconocidas y, a menudo, considerables, por lo que no me sentía cómodo con una especificación heighto "suficiente" arbitrario max-heighty corría el riesgo de contenido de corte que de repente necesita desplazar (si overflow: auto, por ejemplo) . Además, la aceleración y la sincronización se rompen con max-heightsoluciones basadas en la base, ya que la altura utilizada puede alcanzar su valor máximo mucho antes de lo que se necesitaría para max-heightalcanzar 9999px. Y a medida que aumentan las resoluciones de pantalla, la longitud de los píxeles 9999pxdeja un mal sabor en mi boca. Esta solución particular resuelve el problema de una manera elegante, en mi opinión.

Finalmente, aquí se espera que las futuras revisiones de la dirección de CSS necesiten hacer este tipo de cosas de manera aún más elegante: revisar la noción de "computado" vs "usado" y "resuelto" valores, y considerar si las transiciones deberían aplicarse a computado valores, incluidas las transiciones con widthy height(que actualmente reciben un poco de un tratamiento especial).


La respuesta aceptada funciona para la mayoría de los casos, pero no funciona bien cuando divpuede variar mucho en altura: la velocidad de la animación no depende de la altura real del contenido, y puede verse entrecortada.

Aún puede realizar la animación real con CSS, pero necesita usar JavaScript para calcular la altura de los elementos, en lugar de intentar usarlos auto. No se requiere jQuery, aunque es posible que tenga que modificar esto un poco si desea compatibilidad (funciona en la última versión de Chrome :)).

window.toggleExpand = function(element) { if (!element.style.height || element.style.height == ''0px'') { element.style.height = Array.prototype.reduce.call(element.childNodes, function(p, c) {return p + (c.offsetHeight || 0);}, 0) + ''px''; } else { element.style.height = ''0px''; } }

#menu #list { height: 0px; transition: height 0.3s ease; background: #d5d5d5; overflow: hidden; }

<div id="menu"> <input value="Toggle list" type="button" onclick="toggleExpand(document.getElementById(''list''));"> <ul id="list"> <!-- Works well with dynamically-sized content. --> <li>item</li> <li><div style="height: 100px; width: 100px; background: red;"></div></li> <li>item</li> <li>item</li> <li>item</li> </ul> </div>


La solución de altura máxima de Jake funciona bien, si el valor de la altura máxima codificado no es mucho mayor que la altura real (porque de lo contrario hay retrasos no deseados y problemas de tiempo). Por otro lado, si el valor codificado no es mayor que la altura real, el elemento no se abrirá completamente.

La siguiente solución solo para CSS también requiere un tamaño codificado que debería ser más grande que la mayoría de los tamaños reales. Sin embargo, esta solución también funciona si el tamaño real es en algunas situaciones más grande que el tamaño codificado. En ese caso, la transición podría saltar un poco, pero nunca dejará un elemento parcialmente visible. Por lo tanto, esta solución también podría usarse para contenido desconocido, por ejemplo, desde una base de datos, donde simplemente se sabe que el contenido generalmente no es más grande que x píxeles, pero hay excepciones.

La idea es utilizar un valor negativo para el margen inferior (o margen superior para una animación ligeramente diferente) y colocar el elemento de contenido en un elemento intermedio con desbordamiento: oculto. El margen negativo del elemento de contenido reduce la altura del elemento central.

El siguiente código utiliza una transición en el margen inferior de -150px a 0px. Esto solo funciona bien siempre y cuando el elemento de contenido no sea superior a 150 px. Además, utiliza una transición en la altura máxima para el elemento central de 0px a 100%. Finalmente, esto oculta el elemento central si el elemento de contenido es superior a 150 px. Para la altura máxima, la transición solo se usa para retrasar su aplicación en un segundo al cerrarse, no para un efecto visual suave (y, por lo tanto, puede ir de 0px a 100%).

CSS:

.content { transition: margin-bottom 1s ease-in; margin-bottom: -150px; } .outer:hover .middle .content { transition: margin-bottom 1s ease-out; margin-bottom: 0px } .middle { overflow: hidden; transition: max-height .1s ease 1s; max-height: 0px } .outer:hover .middle { transition: max-height .1s ease 0s; max-height: 100% }

HTML:

<div class="outer"> <div class="middle"> <div class="content"> Sample Text <br> Sample Text <br> Sample Text <div style="height:150px">Sample Test of height 150px</div> Sample Text </div> </div> Hover Here </div>

El valor para el margen inferior debe ser negativo y lo más cercano posible a la altura real del elemento de contenido. Si su (valor absoute) es mayor, hay problemas similares de demora y sincronización como con las soluciones de altura máxima, que sin embargo pueden limitarse siempre que el tamaño codificado no sea mucho mayor que el real. Si el valor absoluto para el margen inferior es más pequeño que la altura real, la tansición salta un poco. En cualquier caso, después de la transición, el elemento de contenido se muestra completamente o se elimina por completo.

Para obtener más información, consulte mi blog http://www.taccgl.org/blog/css_transition_display.html#combined_height


Mientras publico esto, ya hay más de 30 respuestas, pero siento que mi respuesta mejora en la respuesta ya aceptada por jake.

No estaba contento con el problema que surge simplemente por el uso de las max-heighttransiciones CSS3, ya que, como observaron muchos comentaristas, debe establecer su max-heightvalor muy cerca de la altura real o tendrá un retraso. Vea este JSFiddle para un ejemplo de ese problema.

Para evitar esto (aunque todavía no use JavaScript), agregué otro elemento HTML que transiciona el transform: translateYvalor de CSS.

Esto significa tanto max-heighty translateYse usan: max-heightpermite que el elemento empuje hacia abajo los elementos debajo de él, mientras que translateYda el efecto "instantáneo" que queremos. El problema con max-heighttodavía existe, pero su efecto se reduce. Esto significa que puede establecer una altura mucho mayor para su max-heightvalor y preocuparse menos por ello.

El beneficio general es que en la transición de regreso (el colapso), el usuario ve la translateYanimación de inmediato, por lo que no importa cuánto tiempo max-heighttome.

Solución como Fiddle

body { font-family: sans-serif; } .toggle { position: relative; border: 2px solid #333; border-radius: 3px; margin: 5px; width: 200px; } .toggle-header { margin: 0; padding: 10px; background-color: #333; color: white; text-align: center; cursor: pointer; } .toggle-height { background-color: tomato; overflow: hidden; transition: max-height .6s ease; max-height: 0; } .toggle:hover .toggle-height { max-height: 1000px; } .toggle-transform { padding: 5px; color: white; transition: transform .4s ease; transform: translateY(-100%); } .toggle:hover .toggle-transform { transform: translateY(0); }

<div class="toggle"> <div class="toggle-header"> Toggle! </div> <div class="toggle-height"> <div class="toggle-transform"> <p>Content!</p> <p>Content!</p> <p>Content!</p> <p>Content!</p> </div> </div> </div> <div class="toggle"> <div class="toggle-header"> Toggle! </div> <div class="toggle-height"> <div class="toggle-transform"> <p>Content!</p> <p>Content!</p> <p>Content!</p> <p>Content!</p> </div> </div> </div>


Ok, entonces creo que se me ocurrió una respuesta súper simple ... no max-height, usa relativeposicionamiento, trabaja en lielementos y es CSS puro. No he probado nada más que Firefox, aunque a juzgar por el CSS, debería funcionar en todos los navegadores.

FIDDLE: http://jsfiddle.net/n5XfG/2596/

CSS

.wrap { overflow:hidden; } .inner { margin-top:-100%; -webkit-transition:margin-top 500ms; transition:margin-top 500ms; } .inner.open { margin-top:0px; }

HTML

<div class="wrap"> <div class="inner">Some Cool Content</div> </div>


Pude hacer esto Tengo una .childy una .parentdiv. El div niño encaja perfectamente dentro de la anchura / altura del padre con absoluteposicionamiento. Entonces animo la translatepropiedad para Ybajar su valor 100%. Su animación muy suave, sin fallos ni inconvenientes como cualquier otra solución aquí.

Algo así, pseudo código.

.parent{ position:relative; overflow:hidden; } /** shown state */ .child { position:absolute;top:0;:left:0;right:0;bottom:0; height: 100%; transition: transform @overlay-animation-duration ease-in-out; .translate(0, 0); } /** Animate to hidden by sliding down: */ .child.slidedown { .translate(0, 100%); /** Translate the element "out" the bottom of it''s .scene container "mask" so its hidden */ }

Se podría especificar un heightsobre .parent, en px, %o dejar como auto. Este div luego enmascara al .childdiv cuando se desliza hacia abajo.


Recientemente he estado haciendo la transición max-heightde los lielementos en lugar de la envoltura ul.

El razonamiento es que el retraso para pequeño max-heightses mucho menos perceptible (si es que lo es) en comparación con el grande max-heights, y también puedo establecer mi max-heightvalor relativo al font-sizede liun número enorme arbitrario en lugar de un gran número arbitrario usando emso rems.

Si el tamaño de mi fuente es 1rem, estableceré mi max-heighten algo como 3rem(para acomodar texto envuelto). Puedes ver un ejemplo aquí:

http://codepen.io/mindfullsilence/pen/DtzjE


Se utiliza max-heightcon diferente transición de aceleración y retraso para cada estado.

HTML:

<a href="#" id="trigger">Hover</a> <ul id="toggled"> <li>One</li> <li>Two</li> <li>Three</li> <ul>

CSS:

#toggled{ max-height: 0px; transition: max-height .8s cubic-bezier(0, 1, 0, 1) -.1s; } #trigger:hover + #toggled{ max-height: 9999px; transition-timing-function: cubic-bezier(0.5, 0, 1, 0); transition-delay: 0s; }

Ver ejemplo: http://jsfiddle.net/0hnjehjc/1/