it-swarm.com.de

Wie kann ich die Höhe ändern: 0; zur Höhe: auto; mit CSS?

Ich versuche, einen <ul> mit CSS-Übergängen nach unten zu verschieben.

Der <ul> beginnt um height: 0;. Beim Hover wird die Höhe auf height:auto; gesetzt. Dies führt jedoch dazu, dass es einfach angezeigt wird: nicht Übergang,

Wenn ich es von height: 40px; bis height: auto; mache, rutscht es auf height: 0; und springt dann plötzlich auf die richtige Höhe.

Wie sonst könnte ich das ohne JavaScript machen?

#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>
1910
Hailwood

Verwenden Sie max-height in der Transformation und nicht height. Und setzen Sie einen Wert auf max-height auf etwas Größeres, als Ihre Box jemals bekommen wird.

Siehe JSFiddle-Demo bereitgestellt von Chris Jordan in einem anderen Antwort hier.

#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>
2518
jake

Sie sollten stattdessen scaleY verwenden.

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

Ich habe eine Vendor-Prefix-Version des obigen Codes für jsfiddle erstellt http://jsfiddle.net/dotnetCarpenter/PhyQc/9/ und Ihre jsfiddle-Version so geändert, dass scaleY anstelle von height verwendet wird http://jsfiddle.net/dotnetCarpenter/7cnfc/206/ .

278
dotnetCarpenter

Sie können derzeit keine Animation für die Höhe durchführen, wenn eine der beteiligten Höhen auto ist. Sie müssen zwei explizite Höhen festlegen.

187
robertc

Die Lösung, die ich immer verwendet habe, war, zuerst die Werte font-size, padding und margin auszublenden und dann zu verkleinern. Es sieht nicht wie ein Wipe aus, funktioniert aber ohne statischen height oder max-height.

Arbeitsbeispiel:

/* 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>
109
Steven Vachon

Ich weiß, dass dies die dreißigste Antwort auf diese Frage ist, aber ich denke, dass es sich lohnt. Dies ist eine Nur-CSS-Lösung mit den folgenden Eigenschaften:

  • Am Anfang gibt es keine Verzögerung, und der Übergang wird nicht vorzeitig gestoppt. Wenn Sie in beiden Richtungen (Erweitern und Reduzieren) in Ihrem CSS eine Übergangsdauer von 300 ms angeben, dauert der Übergang 300 ms.
  • Es ändert die tatsächliche Höhe (im Gegensatz zu transform: scaleY(0)), so dass es das Richtige tut, wenn nach dem reduzierbaren Element Inhalt vorhanden ist.
  • Während (wie in anderen Lösungen) es magische Zahlen gibt (wie "Wähle eine Länge, die höher ist als deine Box"), ist es nicht fatal, wenn deine Annahme endet falsch sein. In diesem Fall sieht die Überblendung möglicherweise nicht besonders gut aus, aber vor und nach der Überblendung ist dies kein Problem: Im erweiterten Zustand (height: auto) hat der gesamte Inhalt immer die richtige Höhe (im Gegensatz zum Beispiel, wenn Sie eine auswählen max-height, das sich als zu niedrig herausstellt). Und im zusammengeklappten Zustand ist die Höhe Null, wie es sollte.

Demo

Hier ist eine Demo mit drei zusammenklappbaren Elementen in unterschiedlichen Höhen, die alle dasselbe CSS verwenden. Möglicherweise möchten Sie auf "Ganze Seite" klicken, nachdem Sie auf "Snippet ausführen" geklickt haben. Beachten Sie, dass das JavaScript nur die CSS-Klasse collapsed umschaltet, es sind keine Messungen erforderlich. (Sie können diese Demo auch ohne JavaScript ausführen, indem Sie ein Kontrollkästchen oder :target verwenden.) Beachten Sie auch, dass der Teil des CSS, der für den Übergang verantwortlich ist, ziemlich kurz ist und das HTML nur ein einziges zusätzliches Wrapper-Element erfordert.

$(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>

Wie funktioniert es?

Tatsächlich gibt es zwei Übergänge, die dies bewirken. Einer von ihnen übergibt den margin-bottom von 0px (im erweiterten Zustand) an -2000px im reduzierten Zustand (ähnlich wie diese Antwort ). Das 2000 hier ist die erste magische Zahl, sie basiert auf der Annahme, dass Ihre Box nicht höher als diese Zahl sein wird (2000 Pixel scheinen eine vernünftige Wahl zu sein).

Die alleinige Verwendung des Übergangs margin-bottom hat zwei Probleme:

  • Wenn Sie tatsächlich eine Box haben, die höher als 2000 Pixel ist, dann wird ein margin-bottom: -2000px nicht alles verbergen - es wird sichtbares Zeug auch in dem zusammengeklappten Fall sein. Dies ist eine kleinere Korrektur, die wir später vornehmen werden.
  • Wenn die tatsächliche Box beispielsweise 1000 Pixel hoch ist und Ihre Überblendung 300 ms lang ist, ist die sichtbare Überblendung bereits nach etwa 150 ms vorbei (oder beginnt in der entgegengesetzten Richtung) 150ms zu spät).

Bei der Behebung dieses zweiten Problems kommt der zweite Übergang ins Spiel, und dieser Übergang zielt konzeptionell auf die Mindesthöhe des Wrappers ("konzeptionell") ab, da wir den min-height nicht verwenden. Eigenschaft dafür; dazu später mehr).

Hier ist eine Animation, die zeigt, wie die Kombination des unteren Randübergangs mit dem minimalen Höhenübergang, beide von gleicher Dauer, einen kombinierten Übergang von voller Höhe zu Höhe Null ergibt, der die gleiche Dauer hat.

animation as described above

Der linke Balken zeigt, wie der negative untere Rand den unteren Rand nach oben drückt und die sichtbare Höhe verringert. Der mittlere Balken zeigt, wie durch die minimale Höhe sichergestellt wird, dass der Übergang im zusammenklappenden Fall nicht vorzeitig endet und im expandierenden Fall nicht zu spät beginnt. Die rechte Leiste zeigt, wie die Kombination der beiden bewirkt, dass die Box in der richtigen Zeit von der vollen Höhe zur Höhe von Null wechselt.

Für meine Demo habe ich mich auf 50px als oberen Mindesthöhenwert festgelegt. Dies ist die zweite magische Zahl, und sie sollte niedriger sein als die Höhe der Box jemals sein würde. 50px scheint auch vernünftig zu sein; Es ist unwahrscheinlich, dass Sie ein Element, das nicht einmal 50 Pixel hoch ist, sehr oft zusammenklappen möchten.

Wie Sie in der Animation sehen können, ist der resultierende Übergang stetig, aber nicht unterscheidbar. In dem Moment, in dem die minimale Höhe der vollen Höhe entspricht, die durch den unteren Rand eingestellt wird, kommt es zu einer plötzlichen Geschwindigkeitsänderung. Dies ist in der Animation sehr auffällig, da für beide Übergänge eine lineare Timing-Funktion verwendet wird und der gesamte Übergang sehr langsam ist. Im aktuellen Fall (meine Demo oben) dauert der Übergang nur 300 ms, und der Übergang zum unteren Rand ist nicht linear. Ich habe mit vielen verschiedenen Timing-Funktionen für beide Übergänge herumgespielt und diejenigen, bei denen ich festgestellt habe, dass sie für die unterschiedlichsten Fälle am besten geeignet sind.

Zwei Probleme müssen noch behoben werden:

  1. der Punkt von oben, an dem Kästchen mit einer Höhe von mehr als 2000 Pixel im zusammengeklappten Zustand nicht vollständig ausgeblendet sind,
  2. und das umgekehrte Problem, bei dem im nicht ausgeblendeten Fall Felder mit einer Höhe von weniger als 50 Pixel zu hoch sind, selbst wenn der Übergang nicht ausgeführt wird, da die Mindesthöhe sie bei 50 Pixel hält.

Wir lösen das erste Problem, indem wir dem Containerelement im reduzierten Fall einen max-height: 0 mit einem 0s 0.3s -Übergang zuweisen. Dies bedeutet, dass es sich nicht wirklich um einen Übergang handelt, sondern dass der max-height verzögert angewendet wird. Es gilt nur, wenn der Übergang beendet ist. Damit dies korrekt funktioniert, müssen wir auch einen numerischen max-height für den entgegengesetzten, nicht komprimierten Zustand auswählen. Im Gegensatz zum 2000px-Fall, bei dem die Auswahl einer zu großen Zahl die Qualität des Übergangs beeinflusst, spielt dies in diesem Fall keine Rolle. Wir können also einfach eine Zahl auswählen, die so hoch ist, dass wir wissen , dass keine Höhe jemals in die Nähe dieser Zahl gelangen wird. Ich habe eine Million Pixel ausgewählt. Wenn Sie der Meinung sind, dass Sie Inhalte mit einer Höhe von mehr als einer Million Pixel unterstützen müssen, dann 1) tut mir leid und 2) fügen Sie einfach ein paar Nullen hinzu.

Das zweite Problem ist der Grund, warum wir min-height nicht für den Übergang der minimalen Höhe verwenden. Stattdessen befindet sich ein Pseudoelement ::after im Container mit einem height, das von 50px auf Null übergeht. Dies hat den gleichen Effekt wie ein min-height: Der Container wird nicht unter die Höhe schrumpfen, die das Pseudoelement derzeit hat. Da wir jedoch height und nicht min-height verwenden, können wir jetzt max-height verwenden (erneut verzögert angewendet), um die tatsächliche Höhe des Pseudoelements auf Null zu setzen, sobald der Übergang abgeschlossen ist über, um sicherzustellen, dass zumindest außerhalb des Übergangs auch kleine Elemente die richtige Höhe haben. Da min-heightstärker als max-height ist, würde dies nicht funktionieren, wenn wir den min-height des Containers anstelle des height des Pseudoelements verwenden würden. Genau wie der max-height im vorherigen Absatz benötigt auch dieser max-height einen Wert für das andere Ende des Übergangs. Aber in diesem Fall können wir nur die 50px auswählen.

Getestet in Chrome (Windows, Mac, Android, iOS), Firefox (Windows, Mac, Android), Edge, IE11 (mit Ausnahme eines flexbox Layout-Problems mit meiner Demo, das ich nicht gemacht habe Debugging) und Safari (Mac, iOS). Apropos Flexbox: Es sollte möglich sein, diese Funktion ohne die Verwendung einer Flexbox auszuführen. Tatsächlich denke ich, dass Sie in IE7 fast alles zum Laufen bringen können - abgesehen von der Tatsache, dass Sie keine CSS-Übergänge haben, was es zu einer ziemlich sinnlosen Übung macht.

77
balpha

Sie können mit ein wenig nicht-semantischem Jiggery-Pokery. Mein üblicher Ansatz besteht darin, die Höhe eines äußeren DIV zu animieren, der ein einzelnes untergeordnetes Element hat. Dies ist ein DIV ohne Stil, der nur zum Messen der Inhaltshöhe verwendet wird.

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>

Man möchte einfach auf den .measuringWrapper verzichten und einfach die Höhe des DIV auf auto setzen und animieren lassen, aber das scheint nicht zu funktionieren (die Höhe wird eingestellt, aber es findet keine Animation statt).

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>

Nach meiner Interpretation ist eine explizite Höhe erforderlich, damit die Animation ausgeführt werden kann. Sie können keine Animation in der Höhe erhalten, wenn eine der Höhen (Start- oder Endhöhe) auto ist.

74
jhurshman

Eine visuelle Problemumgehung zum Animieren der Höhe mithilfe von CSS3-Übergängen besteht darin, stattdessen das Auffüllen zu animieren.

Sie erhalten nicht den vollständigen Wipe-Effekt, aber wenn Sie mit den Übergangsdauer- und Auffüllwerten herumspielen, sollten Sie nah genug dran sein. Wenn Sie height/max-height nicht explizit festlegen möchten, ist dies genau das, wonach Sie suchen.

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/ (von Stiefbands über jsFiddle abgehakt)

47
Catharsis

Meine Problemumgehung besteht darin, die maximale Höhe auf die genaue Höhe des Inhalts zu ändern, um eine reibungslose Animation zu ermöglichen. Anschließend können Sie mithilfe eines TransitionEnd-Rückrufs die maximale Höhe auf 9999px festlegen, damit die Größe des Inhalts frei geändert werden kann.

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>
45
Adam

Die akzeptierte Antwort funktioniert in den meisten Fällen, aber sie funktioniert nicht gut, wenn Ihr div in der Höhe stark variieren kann - die Animationsgeschwindigkeit hängt nicht von der tatsächlichen Höhe des Inhalts ab und kann abgehackt aussehen.

Sie können die eigentliche Animation weiterhin mit CSS ausführen, aber Sie müssen JavaScript verwenden, um die Höhe der Elemente zu berechnen, anstatt zu versuchen, auto zu verwenden. Es ist keine jQuery erforderlich, obwohl Sie dies möglicherweise ein wenig ändern müssen, wenn Sie Kompatibilität wünschen (funktioniert in der neuesten Version von 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>
34
Oleg Vaskevich

Verwenden Sie max-height mit unterschiedlicher Übergangserleichterung und Verzögerung für jeden Status.

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

Siehe Beispiel: http://jsfiddle.net/0hnjehjc/1/

26
malihu

Keine fest codierten Werte.

Kein JavaScript.

Keine Annäherungen.

Der Trick besteht darin, ein verstecktes & dupliziertes div zu verwenden, damit der Browser versteht, was 100% bedeutet.

Diese Methode eignet sich immer dann, wenn Sie das DOM des zu animierenden Elements duplizieren können.

.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>
26
Vivek Maharajh

Die Element.scrollHeight -Eigenschaft, die hier nützlich sein kann und dennoch mit einem reinen CSS-Übergang verwendet werden kann, wurde kaum erwähnt. Die Eigenschaft enthält immer die "volle" Höhe eines Elements, unabhängig davon, ob und wie sein Inhalt aufgrund der reduzierten Höhe überläuft (z. B. _height: 0_).

Als solches ist für ein _height: 0_ (effektiv vollständig zusammengeklapptes) Element seine "normale" oder "volle" Höhe immer noch leicht über seinen scrollHeight -Wert verfügbar (immer ein Pixel Länge).

Wenn für ein solches Element bereits der Übergang eingerichtet ist, wie z. (unter Verwendung von ul gemäß der ursprünglichen Frage):

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

Wir können die gewünschte animierte "Erweiterung" der Höhe nur mit CSS auslösen, und zwar mit etwas wie dem Folgenden (hier wird angenommen, dass sich die Variable ul auf die Liste bezieht):

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

Das ist es. Wenn Sie die Liste reduzieren müssen, reicht eine der beiden folgenden Anweisungen aus:

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

Mein spezieller Anwendungsfall drehte sich um das Animieren von Listen unbekannter und oft beträchtlicher Länge, daher war es mir unangenehm, mich für eine willkürliche "ausreichend große" height oder _max-height_ Spezifikation zu entscheiden und das Risiko einzugehen, dass Inhalte oder Inhalte abgeschnitten werden plötzlich scrollen müssen (wenn _overflow: auto_ zum Beispiel). Bei _max-height_-basierten Lösungen ist die Beschleunigung und das Timing darüber hinaus fehlerhaft, da die verwendete Höhe möglicherweise viel früher ihren Maximalwert erreicht, als es für _max-height_ erforderlich wäre, um _9999px_ zu erreichen. Und mit zunehmender Bildschirmauflösung hinterlassen Pixellängen wie _9999px_ einen schlechten Geschmack in meinem Mund. Diese spezielle Lösung löst das Problem meiner Meinung nach auf elegante Weise.

Zum Schluss hoffen wir, dass zukünftige Überarbeitungen der CSS-Adressautoren diese Art von Dingen noch eleganter ausführen müssen - überdenken Sie den Begriff "berechnet" gegenüber "verwendeten" und "aufgelösten" Werten und überlegen Sie, ob Übergänge für berechnete gelten sollen Werte, einschließlich Übergänge mit width und height (die derzeit eine spezielle Behandlung erhalten).

24
amn

Als ich dies poste, gibt es bereits über 30 Antworten, aber ich glaube, meine Antwort verbessert sich gegenüber der bereits akzeptierten Antwort von Jake.

Ich war nicht zufrieden mit dem Problem, das durch die einfache Verwendung von max-height - und CSS3-Übergängen entsteht, da, wie viele Kommentatoren festgestellt haben, Sie Ihren max-height -Wert sehr nahe an der tatsächlichen Höhe festlegen müssen, sonst erhalten Sie einen verzögern. In this JSFiddle finden Sie ein Beispiel für dieses Problem.

Um dies zu umgehen (während immer noch kein JavaScript verwendet wird), habe ich ein weiteres HTML-Element hinzugefügt, das den CSS-Wert transform: translateY überführt.

Dies bedeutet, dass sowohl max-height als auch translateY verwendet werden: max-height ermöglicht es dem Element, Elemente darunter nach unten zu drücken, während translateY den gewünschten "Sofort" -Effekt ergibt. Das Problem mit max-height besteht weiterhin, aber sein Effekt wird verringert. Dies bedeutet, dass Sie eine viel größere Höhe für Ihren max-height -Wert festlegen und sich weniger Gedanken darüber machen können.

Der allgemeine Vorteil besteht darin, dass der Benutzer beim Übergang zurück in (dem Zusammenbruch) die Animation translateY sofort sieht, so dass es eigentlich egal ist, wie lange die max-height dauert.

Lösung als Geige

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>
21
Andrew Messier

Ok, ich denke, ich habe eine super einfache Antwort gefunden ... nein max-height, verwendet relative Positionierung, arbeitet mit li Elementen und ist reines CSS. Ich habe in nichts anderem als Firefox getestet, obwohl es laut CSS auf allen Browsern funktionieren sollte.

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>
17
VIDesignz

BEARBEITEN: Blättern Sie nach unten, um eine aktualisierte Antwort zu erhalten
Ich habe eine Dropdown-Liste erstellt und diesen Beitrag gesehen ... viele verschiedene Antworten, aber ich entscheide mich, meine Dropdown-Liste auch zu teilen ! Ich habe transform: translateY (y) verwendet, um die Liste in die Ansicht umzuwandeln ...
Sie können mehr im Test sehen
http://jsfiddle.net/BVEpc/4/
Ich habe div hinter jedes li gestellt, weil meine Dropdown-Liste von oben kommt und um ihnen zu zeigen, dass dies erforderlich war, lautet mein Div-Code:

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

und schweben ist:

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

und weil ul height auf den Inhalt gesetzt ist, kann es über Ihren Körperinhalt hinwegkommen, deshalb habe ich das für ul gemacht:

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

und schweben:

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

das zweite Mal nach dem Übergang verzögert sich und wird ausgeblendet, nachdem meine Dropdown-Liste ungefähr geschlossen wurde.
Hoffe, dass später jemand davon profitiert.

EDIT: Ich kann es einfach nicht glauben, dass ppl diesen Prototyp tatsächlich verwendet! Dieses Dropdown-Menü ist nur für ein Untermenü und das ist alles !! Ich habe ein besseres aktualisiert, das zwei Untermenüs für LTR- und RTL-Richtung mit Unterstützung für IE 8 enthalten kann.
Geige für LTR
Geige für RTL
hoffentlich findet jemand dies in Zukunft nützlich.

14
Sijav

Sie können von Höhe: 0 zu Höhe: automatisch wechseln, vorausgesetzt, Sie geben auch minimale und maximale Höhe an.

div.stretchy{
    transition: 1s linear;
}

div.stretchy.hidden{
    height: 0;
}

div.stretchy.visible{
    height: auto;
    min-height:40px;
    max-height:400px;
}
11

Flexbox-Lösung

Vorteile:

  • einfach
  • nein JS
  • weicher Übergang

Nachteile:

  • das Element muss in einen Flexbehälter mit fester Höhe gestellt werden

Die Art und Weise, wie es funktioniert, besteht darin, immer auf Flex-Basis zu arbeiten: Automatisch auf das Element mit dem Inhalt und stattdessen auf Flex-Grow und Flex-Shrink umzustellen.

Bearbeiten: Verbessertes JS Fiddle, inspiriert von der Xbox One-Oberfläche.

* {
  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

10
Lee Comstock

Ich denke, ich habe eine wirklich solide Lösung gefunden

OKAY! Ich weiß, dass dieses Problem so alt ist wie das Internet, aber ich glaube, ich habe eine Lösung, die ich in ein Plugin namens Mutant-Transition verwandelt habe. Meine Lösung legt die Attribute style="" für verfolgte Elemente fest, wenn sich das DOM ändert. Das Endergebnis ist, dass Sie gutes altes CSS für Ihre Übergänge verwenden können und keine hackigen Fixes oder spezielles Javascript verwenden. Sie müssen nur mit data-mutant-attributes="X" festlegen, was Sie auf dem betreffenden Element verfolgen möchten.

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

Das ist es! Diese Lösung verwendet MutationObserver , um Änderungen im DOM zu verfolgen. Aus diesem Grund müssen Sie nichts einrichten oder Javascript verwenden, um Dinge manuell zu animieren. Änderungen werden automatisch nachverfolgt. Da jedoch MutationObserver verwendet wird, erfolgt der Übergang nur in IE11 +.

Geigen!

9
JonTroncoso

Hier ist eine Möglichkeit, von einer beliebigen Anfangshöhe, einschließlich 0, zu Auto (in voller Größe und flexibel) überzugehen, ohne dass ein fester Code pro Knoten oder ein Benutzercode zum Initialisieren erforderlich ist: https: // github .com/csuwildcat/transition-auto . Dies ist im Grunde der heilige Gral für das, was Sie wollen, glaube ich -> http://codepen.io/csuwldcat/pen/kwsdF . Fügen Sie einfach die folgende JS-Datei in Ihre Seite ein, und alles, was Sie danach tun müssen, ist, ein einzelnes boolesches Attribut - reveal="" - zu den Knoten hinzuzufügen/zu entfernen, die Sie erweitern und reduzieren möchten.

Hier ist alles, was Sie als Benutzer tun müssen, sobald Sie den Codeblock unterhalb des Beispielcodes eingefügt haben:

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

Hier ist der Codeblock, der in Ihre Seite aufgenommen werden soll. Danach ist alles Sauce:

Legen Sie diese JS-Datei auf Ihrer Seite ab - es funktioniert alles Just Works ™

/ * Code für die Höhe: auto; Übergang * /

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

/ * Code für 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);
7
csuwldcat

Jakes Antwort zum Animieren der Maximalhöhe ist großartig, aber ich fand die Verzögerung, die durch das Einstellen einer großen Maximalhöhe verursacht wurde, ärgerlich.

Man könnte den reduzierbaren Inhalt in ein inneres Div verschieben und die maximale Höhe berechnen, indem man die Höhe des inneren Div ermittelt (via JQuery wäre es das äußereHeight ()).

$('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');
});

Hier ist ein jsfiddle-Link: http://jsfiddle.net/pbatey/duZpT

Hier ist eine jsfiddle mit der absolut minimal erforderlichen Menge an Code: http://jsfiddle.net/8ncjjxh8/

7
pbatey

Erweitert man die Antwort von @ jake, erreicht der Übergang die maximale Höhe und führt zu einer extrem schnellen Animation. Wenn Sie die Übergänge für beides festlegen: Hover und Off, können Sie die verrückte Geschwindigkeit ein wenig mehr steuern.

Der Schwebeflug ist also, wenn die Maus in den Status wechselt und der Übergang auf der Eigenschaft ohne Schwebeflug die Maus verlassen wird.

Hoffentlich hilft das weiter.

z.B:

.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 */

Hier ist eine Geige: http://jsfiddle.net/BukwJ/

6
jamie

Mir ist klar, dass dieser Thread in die Jahre gekommen ist, aber bei bestimmten Google-Suchanfragen hat er einen hohen Stellenwert, daher denke ich, dass er aktualisiert werden sollte.

Sie können auch nur die Höhe des Elements bestimmen:

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

Sie sollten dieses Javascript sofort nach dem schließenden Tag von target_box in einem Inline-Skript-Tag ablegen.

5
Charley

Ich konnte das machen. Ich habe einen .child & einen .parent div. Das Kind-Div passt sich mit der absolute -Positionierung perfekt an die Breite/Höhe des Elternteils an. Ich animiere dann die Eigenschaft translate, um den Wert von Y nach unten zu verschieben 100%. Es ist eine sehr flüssige Animation, keine Störungen oder Nachteile wie bei jeder anderen Lösung.

So etwas wie Pseudo-Code

.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 */
}

Sie würden height in .parent, in px, % angeben oder als auto belassen. Dieses Div maskiert dann das Div .child, wenn es nach unten rutscht.

5
Josh Ribakoff

Hier ist eine Lösung, die ich gerade in Kombination mit jQuery verwendet habe. Dies funktioniert für die folgende HTML-Struktur:

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

und die Funktion:

    $('#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);
    });

Sie können dann eine Klickfunktion verwenden, um die Höhe mit css() festzulegen und zu entfernen.

$('#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 }
4
j-man86

Ich habe kürzlich den max-height auf die li -Elemente umgestellt und nicht auf den umschließenden ul.

Der Grund dafür ist, dass die Verzögerung für kleinen max-heights (wenn überhaupt) weniger auffällt als für großen max-heights, und ich kann meinen max-height-Wert auch relativ zum font-size der li setzen, anstatt eine beliebige große Zahl zu verwenden ems oder rems.

Wenn meine Schriftgröße 1rem ist, setze ich meinen max-height auf etwas wie 3rem (um umbrochenen Text aufzunehmen). Sie können hier ein Beispiel sehen:

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

4
mindfullsilence

Ich verstehe, dass die Frage nach einer Lösung ohne JavaScript fragt. Aber für die Interessenten ist hier meine Lösung mit nur ein bisschen JS.

oK, das CSS des Elements, dessen Höhe sich standardmäßig ändert, ist auf height: 0; und beim Öffnen auf height: auto; eingestellt. Es hat auch transition: height .25s ease-out;. Aber das Problem ist natürlich, dass es nicht zu oder von height: auto; wechselt.

Ich habe also beim Öffnen oder Schließen die Höhe auf die Eigenschaft scrollHeight des Elements eingestellt. Dieser neue Inline-Stil hat eine höhere Spezifität und setzt sowohl height: auto; als auch height: 0; außer Kraft, und der Übergang wird ausgeführt.

Beim Öffnen füge ich einen transitionend -Ereignis-Listener hinzu, der nur einmal ausgeführt wird, und entferne dann den Inline-Stil, indem er wieder auf height: auto; gesetzt wird. Dadurch kann die Größe des Elements bei Bedarf geändert werden, wie in diesem komplexeren Beispiel mit Untermenüs https://codepen.io/ninjabonsai/pen/GzYyVe

Beim Schließen entferne ich den Inline-Stil direkt nach dem nächsten Ereignisschleife Zyklus, indem ich setTimeout ohne Verzögerung verwende. Dies bedeutet, dass height: auto; vorübergehend überschrieben wird, wodurch der Übergang zurück zu height 0; möglich wird.

const showHideElement = (element, open) => {
  element.style.height = element.scrollHeight + 'px';
  element.classList.toggle('open', open);

  if (open) {
    element.addEventListener('transitionend', () => {
      element.style.removeProperty('height');
    }, {
      once: true
    });
  } else {
    window.setTimeout(() => {
      element.style.removeProperty('height');
    });
  }
}

const menu = document.body.querySelector('#menu');
const list = document.body.querySelector('#menu > ul')

menu.addEventListener('mouseenter', () => showHideElement(list, true));
menu.addEventListener('mouseleave', () => showHideElement(list, false));
#menu>ul {
  height: 0;
  overflow: hidden;
  background-color: #999;
  transition: height .25s ease-out;
}

#menu>ul.open {
  height: auto;
}
<div id="menu">
  <a>hover me</a>
  <ul>
    <li>item</li>
    <li>item</li>
    <li>item</li>
    <li>item</li>
    <li>item</li>
  </ul>
</div>
3
shunryu111

Ich habe nicht alles im Detail gelesen, aber ich hatte dieses Problem vor kurzem und ich habe Folgendes getan:

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

Auf diese Weise können Sie ein Div erstellen, das zunächst Inhalte mit einer Höhe von bis zu 200px anzeigt und dessen Größe beim Schweben mindestens so hoch ist wie der gesamte Inhalt des Divs. Der Div wird nicht 3000px, aber 3000px ist die Grenze, die ich auferlege. Stellen Sie sicher, dass der Übergang auf non: hover gesetzt ist, da sonst möglicherweise ein seltsames Rendering auftritt. Auf diese Weise erbt der: hover vom non: hover.

Der Übergang von px zu% oder zu auto funktioniert nicht. Sie müssen dieselbe Maßeinheit verwenden. Das funktioniert gut für mich. Die Verwendung von HTML5 macht es perfekt ....

Denken Sie daran, dass es immer eine Arbeit gibt ...; )

Hoffe, jemand findet das nützlich

3
work.stella84

Dies ist nicht gerade eine "Lösung" für das Problem, sondern eher eine Problemumgehung. Es funktioniert nur so, wie es mit Text geschrieben wurde, kann aber, da ich mir sicher bin, geändert werden, um mit anderen Elementen zu arbeiten.

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

Hier ist ein Beispiel: http://codepen.io/overthemike/pen/wzjRKa

Im Wesentlichen setzen Sie die Schriftgröße auf 0 und ändern diese anstelle der Höhe oder der maximalen Höhe oder scaleY () usw. schnell genug, um die gewünschte Höhe zu erreichen. Das Umwandeln der tatsächlichen Höhe mit CSS in auto ist derzeit nicht möglich, das Umwandeln des Inhalts innerhalb von CSS ist jedoch möglich, daher der Schriftgrößenübergang.

  • Hinweis - es gibt IS Javascript im Codepen, aber es dient nur dazu, CSS-Klassen beim Klicken für das Akkordeon hinzuzufügen/zu entfernen. Dies kann mit versteckten Optionsfeldern geschehen, aber ich habe mich nicht darauf konzentriert, sondern nur auf die Höhenumwandlung.
3
Mike S.

Es scheint keine richtige Lösung zu geben. max-height Ansatz ist ziemlich gut, funktioniert aber nicht gut für die Ausblendphase - es wird eine merkliche Verzögerung geben, wenn Sie die Höhe des Inhalts nicht kennen.

Ich denke, der beste Weg ist, max-height zu verwenden, aber nur für die Show-Phase. Und keine Animation zum Verstecken zu verwenden. In den meisten Fällen sollte es nicht entscheidend sein.

max-height sollte auf einen ziemlich großen Wert gesetzt werden, um sicherzustellen, dass der Inhalt passt. Die Animationsgeschwindigkeit kann über die Dauer von transition (speed = max-height / duration) gesteuert werden. Die Geschwindigkeit hängt nicht von der Größe des Inhalts ab. Die Zeit, die zum Anzeigen des gesamten Inhalts benötigt wird, hängt von seiner Größe ab.

document.querySelector("button").addEventListener(
  "click", 
  function(){
    document.querySelector("div").classList.toggle("hide");
  }
)
div {    
    max-height: 20000px;
    transition: max-height 3000ms;
    overflow-y: hidden;
}

.hide {
    max-height: 0;
    transition: none;
}
<button>Toggle</button>
<div class="hide">Lorem ipsum dolor sit amet, ius solet dignissim honestatis ad. Mea quem tibique intellegat te. Insolens deterruisset cum ea. Te omnes percipit consulatu eos. Vix novum primis salutatus no, eam denique sensibus et, his ipsum senserit ne. Lorem ipsum dolor sit amet, ius solet dignissim honestatis ad. Mea quem tibique intellegat te. Insolens deterruisset cum ea. Te omnes percipit consulatu eos. Vix novum primis salutatus no, eam denique sensibus et, his ipsum senserit ne. Lorem ipsum dolor sit amet, ius solet dignissim honestatis ad. Mea quem tibique intellegat te. Insolens deterruisset cum ea. Te omnes percipit consulatu eos. Vix novum primis salutatus no, eam denique sensibus et, his ipsum senserit ne. Lorem ipsum dolor sit amet, ius solet dignissim honestatis ad. Mea quem tibique intellegat te. Insolens deterruisset cum ea. Te omnes percipit consulatu eos. Vix novum primis salutatus no, eam denique sensibus et, his ipsum senserit ne. Lorem ipsum dolor sit amet, ius solet dignissim honestatis ad. Mea quem tibique intellegat te. Insolens deterruisset cum ea. Te omnes percipit consulatu eos. Vix novum primis salutatus no, eam denique sensibus et, his ipsum senserit ne. Lorem ipsum dolor sit amet, ius solet dignissim honestatis ad. Mea quem tibique intellegat te. Insolens deterruisset cum ea. Te omnes percipit consulatu eos. Vix novum primis salutatus no, eam denique sensibus et, his ipsum senserit ne. Lorem ipsum dolor sit amet, ius solet dignissim honestatis ad. Mea quem tibique intellegat te. Insolens deterruisset cum ea. Te omnes percipit consulatu eos. Vix novum primis salutatus no, eam denique sensibus et, his ipsum senserit ne. Lorem ipsum dolor sit amet, ius solet dignissim honestatis ad. Mea quem tibique intellegat te. Insolens deterruisset cum ea. Te omnes percipit consulatu eos. Vix novum primis salutatus no, eam denique sensibus et, his ipsum senserit ne. Lorem ipsum dolor sit amet, ius solet dignissim honestatis ad. Mea quem tibique intellegat te. Insolens deterruisset cum ea. Te omnes percipit consulatu eos. Vix novum primis salutatus no, eam denique sensibus et, his ipsum senserit ne. 
</div>
2
Andrej

Die Max-Height-Lösung von Jake funktioniert gut, wenn der angegebene fest codierte Max-Height-Wert nicht viel größer als die tatsächliche Höhe ist (da es sonst zu unerwünschten Verzögerungen und Timing-Problemen kommt). Ist der hartcodierte Wert hingegen versehentlich nicht größer als die tatsächliche Höhe, öffnet sich das Element nicht vollständig.

Die folgende Nur-CSS-Lösung erfordert auch eine fest codierte Größe, die größer sein sollte als die meisten der vorkommenden realen Größen. Diese Lösung funktioniert jedoch auch, wenn die tatsächliche Größe in einigen Situationen größer ist als die fest codierte Größe. In diesem Fall springt der Übergang möglicherweise etwas, lässt jedoch niemals ein teilweise sichtbares Element zurück. So könnte diese Lösung auch für unbekannte Inhalte verwendet werden, z. aus einer Datenbank, in der Sie nur wissen, dass der Inhalt normalerweise nicht größer als x Pixel ist, aber es gibt Ausnahmen.

Die Idee ist, einen negativen Wert für Rand-Unten (oder Rand-Oben für eine geringfügig abweichende Animation) zu verwenden und das Inhaltselement in einem mittleren Element mit Überlauf zu platzieren: hidden. Der negative Rand des Inhaltselements verringert somit die Höhe des mittleren Elements.

Der folgende Code verwendet einen Übergang am unteren Rand von -150 Pixel auf 0 Pixel. Dies allein funktioniert einwandfrei, solange das Inhaltselement nicht höher als 150px ist. Zusätzlich wird ein Übergang auf maximaler Höhe für das mittlere Element von 0px auf 100% verwendet. Dadurch wird das mittlere Element endgültig ausgeblendet, wenn das Inhaltselement größer als 150 Pixel ist. Bei maximaler Höhe wird der Übergang nur verwendet, um die Anwendung beim Schließen um eine Sekunde zu verzögern, nicht um einen reibungslosen visuellen Effekt zu erzielen (und kann daher von 0px bis 100% ausgeführt werden).

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>

Der Wert für den unteren Rand sollte negativ sein und der tatsächlichen Höhe des Inhaltselements möglichst nahe kommen. Wenn es (absoute value) größer ist, gibt es ähnliche Verzögerungs- und Zeitprobleme wie bei Lösungen mit maximaler Höhe, die jedoch begrenzt werden können, solange die fest codierte Größe nicht viel größer als die tatsächliche ist. Wenn der absolute Wert für margin-bottom kleiner als die tatsächliche Höhe ist, springt die Tansition ein bisschen. In jedem Fall wird das Inhaltselement nach dem Übergang entweder vollständig angezeigt oder vollständig entfernt.

Weitere Details finden Sie in meinem Blog-Beitrag http://www.taccgl.org/blog/css_transition_display.html#combined_height

2

Stellen Sie die Höhe auf Auto und ändern Sie die maximale Höhe.

Getestet auf 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%; /**/
}
1
will Farrell

KLEINE JAVASCRIPT + SCSS-LÖSUNG

Ich benutze normalerweise eine ganz andere Sichtweise und ein (sehr) kleines Javascript. Die Sache ist:

  • was wir wirklich wollen, ist die Veränderung der Körpergröße

  • Die Höhe ist die Summe aller Listenelemente im Untermenü

  • Normalerweise kennen wir die Höhe eines Listenelements, da wir es formatieren

Meine Lösung gilt also für "normale" Untermenüs, in denen die Elementnamen nur eine Zeile haben. Auf jeden Fall könnte man mit etwas mehr js sogar mehr als 1 Zeilennamen unterbringen.

Grundsätzlich zähle ich einfach die Untermenüs und wende bestimmte Klassen entsprechend an. Dann gib den Ball an css weiter. Also zum Beispiel:

var main_menu = $('.main-menu');
var submenus = $('.main-menu').find('.submenu');
submenus.each(function(index,item){
   var i = $(item);
   i.addClass('has-' + i.find('li').length + '-children');
});

Sie können natürlich jede Klasse/jeden Selektor verwenden. An dieser Stelle haben wir folgende Untermenüs:

<ul class="submenu has-3-children">
   <li></li>
   <li></li>
   <li></li>
</ul>

Und unser CSS sieht so aus:

.submenu{
   //your styles [...]
   height:0;
   overflow:hidden;
   transition: all 200ms ease-in-out; //assume Autoprefixer is used
}

Wir werden auch einige SCSS-Variablen wie diese haben (beliebiges Beispiel):

$sub_item_height:30px;
$sub_item_border:2px;

An diesem Punkt können wir, wenn angenommen wird, dass geöffnete Hauptmenüelemente eine Klasse wie "geöffnet" oder dergleichen (Ihre Implementierungen ...) erhalten, so etwas tun:

//use a number of children reasonably high so it won't be overcomed by real buttons
.main-menu .opened .submenu{
   &.has-1-children{ height:   $sub_item_height*1  + $sub_item_border*1;  }
   &.has-2-children{ height:   $sub_item_height*2  + $sub_item_border*2;  }
   &.has-3-children{ height:   $sub_item_height*3  + $sub_item_border*3;  }
   //and so on....
}

Oder, um es zu verkürzen:

.main-menu .opened .submenu{
   @for $i from 1 through 12{//12 is totally arbitrary
      &.has-#{$i}-children { height: $menu_item_height * $i + $menu_item_border * $i; }
   }
}

Meistens erledigt dies die Arbeit. Ich hoffe es hilft!

0
Luca Reghellin

Dies ist ein normales Problem, das ich so gelöst habe

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

Versuchen Sie, die Verzögerung im geschlossenen Zustand auf einen negativen Wert zu setzen und ein wenig mit dem Wert zu spielen. Sie werden den Unterschied bemerken. Man kann fast das menschliche Auge zum Lügen bringen;).

Es funktioniert in den meisten Browsern, ist aber für mich gut genug. Es ist seltsam, aber geben Sie einige Ergebnisse.

.expandable {
    max-height: 0px;
    overflow: hidden;
    transition: all 1s linear -0.8s;
}

button:hover ~ .expandable {
    max-height: 9000px;
    transition: all 1s ease-in-out;
}
0
Ivan Peshev