Hoe kan ik de hoogte overzetten: 0; naar hoogte: automatisch; CSS gebruiken?

Ik probeer een <ul>dia naar beneden te maken met CSS-overgangen.

De <ul>begint op height: 0;. Bij zweven is de hoogte ingesteld op height:auto;. Dit zorgt er echter voor dat het gewoon verschijnt, nietovergang,

Als ik het doe van height: 40px;naar height: auto;, dan schuift het omhoog naar height: 0;, en spring dan plotseling naar de juiste hoogte.

Hoe zou ik dit anders kunnen doen zonder JavaScript te gebruiken?

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

1, Autoriteit 100%

Gebruik max-heightin de overgang en niet height. En stel een waarde in op max-heightnaar iets groters dan uw doos zal ooit krijgen.

Zie JSFiddle Demo verstrekt door Chris Jordanië in een andere answer 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>

2, Autoriteit 12%

U moet in plaats daarvan schalen gebruiken.

ul {
  background-color: #eee;
  transform: scaleY(0);    
  transform-origin: top;
  transition: transform 0.26s ease;
}
p:hover ~ ul {
  transform: scaleY(1);
}
<p>Hover This</p>
<ul>
  <li>Coffee</li>
  <li>Tea</li>
  <li>Milk</li>
</ul>

Antwoord 3, autoriteit 7%

Je kunt momenteel niet animeren op hoogte wanneer een van de betrokken hoogten autois, je moet twee expliciete hoogten instellen.


Antwoord 4, autoriteit 5%

De oplossing die ik altijd heb gebruikt, was om eerst de waarden voor font-size, paddingen marginte verkleinen. Het ziet er niet hetzelfde uit als een wipe, maar het werkt zonder een statische heightof max-height.

Werkvoorbeeld:

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

Antwoord 5, autoriteit 4%

Ik weet dat dit het dertigste antwoord op deze vraag is, maar ik denk dat het het waard is, dus hier komt het. Dit is een alleen CSS-oplossing met de volgende eigenschappen:

  • Er is geen vertraging aan het begin en de overgang stopt niet vroeg. In beide richtingen (uitvouwen en samenvouwen), als u een overgangsduur van 300 ms specificeert in uw CSS, dan duurt de overgang 300 ms, punt uit.
  • Het verandert de werkelijke hoogte (in tegenstelling tot transform: scaleY(0)), dus het doet het juiste als er inhoud is na het inklapbare element.
  • Hoewel (zoals in andere oplossingen) er zijnmagische getallen (zoals “kies een lengte die hoger is dan je doos ooit zal zijn”), is het niet fataal als je aanname uiteindelijk mis. De overgang ziet er in dat geval misschien niet geweldig uit, maar voor en na de overgang is dit geen probleem: in de uitgebreide (height: auto) staat heeft de hele inhoud altijd de juiste hoogte (in tegenstelling tot bijv. als je een max-heightkiest die te laag blijkt te zijn). En in de ingeklapte toestand is de hoogte nul zoals het hoort.

Demo

Hier is een demo met drie inklapbare elementen, alle verschillende hoogtes, die allemaal dezelfde CSS gebruiken. Mogelijk wilt u klikken op “Volledige pagina” na het klikken op “Snippet”. Merk op dat het JavaScript alleen de collapsedCSS-klasse schakelt, er is geen meten. (U kunt deze exacte demo zonder javascript doen met behulp van een selectievakje of :target). Merk ook op dat het deel van de CSS dat verantwoordelijk is voor de overgang vrij kort is en de HTML alleen een enkel extra wikkelelement vereist.

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

Antwoord 6, autoriteit 3%

Dat kan, met een beetje niet-semantische jiggery-pokery. Mijn gebruikelijke benadering is om de hoogte van een buitenste DIV te animeren die een enkel kind heeft, een stijlloze DIV die alleen wordt gebruikt voor het meten van de inhoudshoogte.

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>

Antwoord 7, autoriteit 2%

Een visuele oplossing voor het animeren van hoogte met behulp van CSS3-overgangen is om in plaats daarvan de opvulling te animeren.

Je krijgt niet helemaal het volledige wipe-effect, maar door te spelen met de overgangsduur en opvullingswaarden zou je dichtbij genoeg moeten komen. Als je de hoogte/max-hoogte niet expliciet wilt instellen, zou dit moeten zijn wat je zoekt.

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/stephband boven jsFiddle)


Antwoord 8, autoriteit 2%

Het geaccepteerde antwoord werkt in de meeste gevallen, maar het werkt niet goed wanneer uw divsterk in hoogte kan variëren — de animatiesnelheid is niet afhankelijk van de werkelijke hoogte van de inhoud, en het kan er schokkerig uitzien.

Je kunt nog steeds de daadwerkelijke animatie uitvoeren met CSS, maar je moet JavaScript gebruiken om de hoogte van de items te berekenen, in plaats van te proberen autote gebruiken. Er is geen jQuery vereist, hoewel je dit misschien een beetje moet aanpassen als je compatibiliteit wilt (werkt in de nieuwste versie van 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>

Antwoord 9, autoriteit 2%

Mijn tijdelijke oplossing is om de maximale hoogte over te zetten naar de exacte inhoudshoogte voor een mooie vloeiende animatie, en vervolgens een callback transitieEnd te gebruiken om de maximale hoogte in te stellen op 9999px, zodat de inhoud vrijelijk kan worden vergroot/verkleind.

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>

Antwoord 10

Er was weinig melding gemaakt van het Element.prototype.scrollHeighteigenschap die hier nuttig kan zijn en nog steeds kan worden gebruikt met een pure CSS overgang, hoewel ondersteuning voor scripting natuurlijk nodig zou zijn . Het gebouw altijd de “volledige” lengte van een element, ongeacht of en hoe de inhoud overstroomt als resultaat van ingeklapte lengte (bijvoorbeeld height: 0).

Als zodanig, een height: 0(daadwerkelijk volledig samengevouwen) element, zijn “normale” of “full” height nog beschikbaar via de scrollHeightwaarde ( steevast een pixel length).

Voor een dergelijk element, in de veronderstelling dat al de opzet zoals bijvoorbeeld transitie (Met ulvanaf oorspronkelijke vraag):

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

kan leiden gewenste geanimeerd “uitbreiding” van de hoogte, met alleen CSS, met iets als de volgende (veronderstel hier ulvariabele betreft de lijst):

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

Dat is het. Als u nodig hebt om de lijst samen te vouwen, een van de twee volgende uitspraken doen:

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

Mijn specifieke use case draaide om het animeren van lijsten van onbekende en vaak aanzienlijke lengtes, dus ik voelde me niet op mijn gemak bij een willekeurige “groot genoeg” heightof max-heightspecificatie en riskeert u afgesneden inhoud of inhoud die u plotseling moet scrollen (bijvoorbeeld als overflow: auto). Bovendien wordt de easing en timing verbroken met max-height-gebaseerde oplossingen, omdat de gebruikte hoogte zijn maximale waarde veel eerder kan bereiken dan het zou duren voor max-heightom 9999pxte bereiken. En naarmate de schermresoluties groeien, laten pixellengtes zoals 9999pxeen vieze smaak in mijn mond achter. Deze specifieke oplossing lost het probleem naar mijn mening op een elegante manier op.

Ten slotte hopen we dat toekomstige revisies van CSS-adresauteurs dit soort dingen nog eleganter moeten doen — kijk opnieuw naar het begrip “berekende” versus “gebruikte” en “opgeloste” waarden, en overweeg of overgangen zouden moeten zijn van toepassing op berekende waarden, inclusief overgangen met widthen height(die momenteel een beetje een speciale behandeling krijgen).


Antwoord 11

Gebruik max-heightmet verschillende overgangsversoepeling en vertraging voor elke 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;
}

Zie voorbeeld: http://jsfiddle.net/0hnjehjc/1/


12

Geen harde gecodeerde waarden.

No JavaScript.

Geen benaderingen.

De truc is om een ​​verborgen en ampère te gebruiken; gedupliceerd divom de browser te krijgen om te begrijpen wat 100% betekent.

Deze methode is geschikt wanneer u de DOM van het element kunt dupliceren dat u wilt animeren.

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

Antwoord 13

Terwijl ik dit post, zijn er al meer dan 30 antwoorden, maar ik voel dat mijn antwoord beter is dan het reeds geaccepteerde antwoordvan jake.

Ik was niet tevreden met het probleem dat ontstaat door simpelweg max-heighten CSS3-overgangen te gebruiken, aangezien, zoals veel commentatoren opmerkten, je je max-heightmoet instellen waarde heel dicht bij de werkelijke hoogte of je krijgt een vertraging. Zie deze JSFiddlevoor een voorbeeld van dat probleem.

Om dit te omzeilen (terwijl ik nog steeds geen JavaScript gebruik), heb ik nog een HTML-element toegevoegd dat de transform: translateYCSS-waarde overgaat.

Dit betekent dat zowel max-heightals translateYworden gebruikt: max-heightstaat het element toe om elementen eronder naar beneden te duwen, terwijl translateYgeeft het “instant” effect dat we willen. Het probleem met max-heightbestaat nog steeds, maar het effect is minder.
Dit betekent dat je een veel grotere hoogte kunt instellen voor je max-height-waarde en je er minder zorgen over hoeft te maken.

Het algemene voordeel is dat de gebruiker bij de overgang terug naar binnen (de ineenstorting), de translateY-animatie onmiddellijk ziet, dus het maakt niet echt uit hoe lang de max-heightduurt.

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

14

OK, dus ik denk dat ik met een super eenvoudig antwoord bedacht …
NEE max-height, gebruikt relativePositionering, Werkt op liElements & AMP; is pure CSS.
Ik heb niets anders getoond, maar Firefox, hoewel het te oordelen naar de CSS, zou het aan alle browsers moeten werken.

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>

Antwoord 15

BEWERK: Scroll naar beneden voor een bijgewerkt antwoord
Ik was een vervolgkeuzelijst aan het maken en zag dit bericht … veel verschillende antwoorden, maar ik besluit ook mijn vervolgkeuzelijst te delen, … Het is niet perfect, maar het zal in ieder geval alleen css gebruiken voor vervolgkeuzelijsten! Ik heb transform:translateY(y) gebruikt om de lijst te transformeren naar de weergave …
U kunt meer zien in de test
http://jsfiddle.net/BVEpc/4/
Ik heb div achter elke li geplaatst omdat mijn vervolgkeuzelijst van boven komt en om ze goed te laten zien was dit nodig, mijn div-code is:

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

en zweven is:

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

en omdat ul hoogte is ingesteld op de inhoud die het over je lichaamsinhoud kan krijgen, daarom deed ik dit voor ul:

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

en zweven:

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

de tweede keer na de overgang is vertraging en het wordt verborgen nadat mijn vervolgkeuzelijst levend is gesloten …
Hoop dat later iemand hiervan profiteert.

EDIT: ik kan gewoon niet geloven dat ppl dit prototype daadwerkelijk gebruikt! dit vervolgkeuzemenu is slechts voor één submenu en dat is alles!!
Ik heb een betere bijgewerkt die twee submenu’s kan hebben voor zowel ltr- als rtl-richting met IE 8-ondersteuning.
Fiddle voor LTR
Fiddle voor RTL
hopelijk vindt iemand dit in de toekomst nuttig.


Antwoord 16

Je kunt overschakelen van height:0 naar height:auto, op voorwaarde dat je ook min-height en max-height opgeeft.

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

Antwoord 17

Uitbreidend op het antwoord van @jake, de overgang gaat helemaal naar de maximale hoogtewaarde, wat een extreem snelle animatie veroorzaakt – als je de overgangen instelt voor zowel :hover als off, kun je de gekke snelheid een beetje meer regelen .

Dus de li:hover is wanneer de muis de status binnengaat en dan zal de overgang op de niet-gehoverde eigenschap de muisverlaten zijn.

Hopelijk helpt dit je iets.

bijvoorbeeld:

.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 is een viool: http://jsfiddle.net/BukwJ/


Antwoord 18

Flexbox-oplossing

Pluspunten:

  • eenvoudig
  • geen JS
  • soepele overgang

Nadelen:

  • element moet in een flexcontainer met vaste hoogte worden geplaatst

De manier waarop het werkt is door altijd flex-basis te hebben: auto op het element met inhoud, en in plaats daarvan flex-grow en flex-shrink over te zetten.

Bewerken: verbeterde JS Fiddle geïnspireerd op de Xbox One-interface.

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

Antwoord 19

Hier is een manier om over te stappen van elke starthoogte, inclusief 0, naar automatisch (volledige grootte en flexibel) zonder dat er per knooppunt een vaste code nodig is of een gebruikerscode om te initialiseren: https://github.com/csuwildcat/transition-auto. Dit is eigenlijk de heilige graal voor wat je wilt, geloof ik –> http://codepen.io/csuwldcat/pen/kwsdF. Sla gewoon het volgende JS-bestand op je pagina en het enige wat je daarna hoeft te doen is een enkel booleaans attribuut – reveal=""– toevoegen/verwijderen van de knooppunten die je wilt uitvouwen en inkrimpen.

Dit is alles wat u als gebruiker hoeft te doen, zodra u het codeblok onder de voorbeeldcode heeft opgenomen:

/*** 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 is het codeblok dat je in je pagina moet opnemen, daarna is het allemaal jus:

Zet dit JS-bestand op uw pagina – het werkt allemaal gewoon™

/* Code voor hoogte: auto; overgang */

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

Antwoord 20

Ik denk dat ik een heel solide oplossing heb bedacht

Oké! Ik weet dat dit probleem zo oud is als het internet, maar ik denk dat ik een oplossing heb die ik heb omgezet in een plug-in genaamd mutant -overgang. Mijn oplossing stelt de style=""-attributen in voor bijgehouden elementen wanneer er een wijziging is in de DOM. het eindresultaat is dat je goede oude CSS kunt gebruiken voor je overgangen en geen hacky-fixes of speciaal javascript kunt gebruiken. Het enige dat u hoeft te doen is instellen wat u wilt bijhouden op het betreffende element met behulp van data-mutant-attributes="X".

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

Dat is het! Deze oplossing gebruikt MutationObserverom wijzigingen in de DOM te volgen. Hierdoor hoef je niet echt iets in te stellen of javascript te gebruiken om dingen handmatig te animeren. Wijzigingen worden automatisch bijgehouden. Omdat het echter MutationObserver gebruikt, zal dit alleen overgaan in IE11+.

Viooltjes!


21

Ik realiseer me dat deze draad oud wordt, maar het staat hoog op bepaalde Google-zoekopdrachten, dus ik denk dat het de moeite waard is om bij te werken.

U krijgt ook gewoon de eigen lengte van het element:

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

U moet dit JavaScript onmiddellijk na de sluitingstag van Target_box in een Inline Script-tag dumpen.


22

Ik heb onlangs de max-heightovergeslagen op de liELEMENTEN in plaats van de inpakken ul.

De redenering is dat de vertraging voor kleine max-heightsveel minder merkbaar is (indien helemaal) in vergelijking met grote max-heights, en ik kan ook mijn max-heightWaarde ten opzichte van de font-sizevan de liin plaats van een willekeurig enorm getal met behulp van emsof rems.

Als mijn lettergrootte 1remis, zal ik mijn max-heightinstellen op zoiets als 3rem(om ingepakte tekst te huisvesten). U kunt hier een voorbeeld zien:

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


23

Ik heb een antwoord gepost met wat JavaScript en ben gedownded, dus raakte geïrriteerd en opnieuw geprobeerd en heeft het alleen met CSS gekraakt!

Deze oplossing gebruikt een paar ‘technieken’:

  • padding-bottom:100%‘hack’ waarbij percentages worden gedefinieerd in termen van de huidige breedte van het element. Meer informatie over deze techniek.
  • zwevende krimp-verpakking, (een extra div nodig om de vlotter clearing hack toe te passen)
  • Ongedemantelijk gebruik van https://caniuse.com/#Feat=CSS-writing-mode en enkele transformaties om het ongedaan te maken (hiermee kan het gebruik van de vulling hack boven in een verticale context)

De upshot is echter dat we uitvoerend overgang krijgen met behulp van CSS alleen en een enkele overgangsfunctie om de overgang soepel te bereiken; De Heilige Graal!

Natuurlijk is er een nadeel! Ik kan niet werken hoe u de breedte kunt besturen waarmee inhoud wordt afgesneden (overflow:hidden); Vanwege de hack van de vatding-bodem zijn de breedte en hoogte nauw verwant. Er kan echter een manier zijn, dus zal eraan terugkomen.

https://jsfiddle.net/Eoghanm/n1RP3ZB4/28/

body {
  padding: 1em;
}
.trigger {
  font-weight: bold;
}
/* .expander is there for float clearing purposes only */
.expander::after {
  content: '';
  display: table;
  clear: both;
}
.outer {
  float: left; /* purpose: shrink to fit content */
  border: 1px solid green;
  overflow: hidden;
}
.inner {
  transition: padding-bottom 0.3s ease-in-out;  /* or whatever crazy transition function you can come up with! */
  padding-bottom: 0%;  /* percentage padding is defined in terms of width. The width at this level is equal to the height of the content */
  height: 0;
  /* unfortunately, change of writing mode has other bad effects like orientation of cursor */
  writing-mode: vertical-rl;
  cursor: default; /* don't want the vertical-text (sideways I-beam) */
  transform: rotate(-90deg) translateX(-100%);  /* undo writing mode */
  transform-origin: 0 0;
  margin: 0;  /* left/right margins here will add to height */
}
.inner > div { white-space: nowrap; }
.expander:hover .inner,  /* to keep open when expanded */
.trigger:hover+.expander .inner {
  padding-bottom: 100%;
}
<div class="trigger">HoverMe</div>
<div class="expander">
  <div class="outer">
    <div class="inner">
      <div>First Item</div>
      <div>Content</div>
      <div>Content</div>
      <div>Content</div>
      <div>Long Content can't be wider than outer height unfortunately</div>
      <div>Last Item</div>
    </div>
  </div>
</div>
<div>
  after content</div>
</div>

Antwoord 24

Je zou dit kunnen doen door een omgekeerde (samengevouwen) animatie te maken met clip-path.

#child0 {
    display: none;
}
#parent0:hover #child0 {
    display: block;
    animation: height-animation;
    animation-duration: 200ms;
    animation-timing-function: linear;
    animation-fill-mode: backwards;
    animation-iteration-count: 1;
    animation-delay: 200ms;
}
@keyframes height-animation {
    0% {
        clip-path: polygon(0% 0%, 100% 0.00%, 100% 0%, 0% 0%);
    }
    100% {
        clip-path: polygon(0% 0%, 100% 0.00%, 100% 100%, 0% 100%);
    }
}
<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>

Antwoord 25

Oplossing in één zin: Gebruik opvulovergang. Het is genoeg voor de meeste gevallen, zoals accordeon, en nog beter omdat het snel is omdat de opvulwaarde vaak niet groot is.

Als u wilt dat het animatieproces beter is, verhoogt u gewoon de opvulwaarde.

.parent{ border-top: #999 1px solid;}
h1{ margin: .5rem; font-size: 1.3rem}
.children {
  height: 0;
  overflow: hidden;
  background-color: #dedede;
  transition: padding .2s ease-in-out, opacity .2s ease-in-out;
  padding: 0 .5rem;
  opacity: 0;
}
.children::before, .children::after{ content: "";display: block;}
.children::before{ margin-top: -2rem;}
.children::after{ margin-bottom: -2rem;}
.parent:hover .children {
  height: auto;
  opacity: 1;
  padding: 2.5rem .5rem;/* 0.5 + abs(-2), make sure it's less than expected min-height */
}
<div class="parent">
  <h1>Hover me</h1>
  <div class="children">Some content
    <br>Some content
    <br>Some content
    <br>Some content
    <br>Some content
    <br>Some content
    <br>
  </div>
</div>
<div class="parent">
  <h1>Hover me(long content)</h1>
  <div class="children">Some content
    <br>Some content<br>Some content
    <br>Some content<br>Some content
    <br>Some content<br>Some content
    <br>Some content<br>Some content
    <br>Some content<br>Some content
    <br>
  </div>
</div>
<div class="parent">
  <h1>Hover me(short content)</h1>
  <div class="children">Some content
    <br>Some content
    <br>Some content
    <br>
  </div>
</div>

Antwoord 26

Hier is een oplossing die ik zojuist heb gebruikt in combinatie met jQuery. Dit werkt voor de volgende HTML-structuur:

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

en de functie:

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

Je zou dan een klikfunctie kunnen gebruiken om de hoogte in te stellen en te verwijderen met 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 }

Antwoord 27

Ik begrijp dat de vraag om een oplossing vraagt zonder JavaScript. Maar voor degenen die geïnteresseerd zijn, hier is mijn oplossing met slechts een klein beetje JS.

ok, dus de css van het element waarvan de hoogte standaard verandert, is ingesteld op height: 0;en als het open is height: auto;. Het heeft ook transition: height .25s ease-out;. Maar het probleem is natuurlijk dat het niet overgaat van of naar height: auto;

Dus wat ik heb gedaan, is bij het openen of sluiten de hoogte instellen op de eigenschap scrollHeightvan het element. Deze nieuwe inline-stijl zal een hogere specificiteit hebben en zowel height: auto;als height: 0;overschrijven en de overgang wordt uitgevoerd.

Bij het openen voeg ik een transitionendgebeurtenislistener toe die slechts één keer wordt uitgevoerd en verwijder vervolgens de inline-stijl en zet deze terug naar height: auto;waardoor het element de grootte kan wijzigen indien nodig, zoals in dit complexere voorbeeld met submenu’s https://codepen.io/ninjabonsai/pen/ GzYyVe

Bij het sluiten verwijder ik de inline-stijl direct na de volgende gebeurtenislus cyclus door setTimeout zonder vertraging te gebruiken. Dit betekent dat height: auto;tijdelijk wordt overschreven, wat de overgang naar height 0;

mogelijk maakt

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>

Antwoord 28

Ik heb niet alles in detail gelezen, maar ik heb onlangs dit probleem gehad en ik heb het volgende gedaan:

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

Hierdoor kunt u een div hebben die in eerste instantie inhoud tot 200px hoogte laat zien en bij hover wordt de grootte minstens zo hoog als de gehele inhoud van de div. De Div wordt geen 3000px maar 3000px is de limiet die ik opleg. Zorg ervoor dat de overgang op de non :hover staat, anders krijg je misschien een vreemde weergave. Op deze manier erft de :hover van de niet :hover.

Overgang werkt niet van px naar % of naar auto. U moet dezelfde maateenheid gebruiken.

Other episodes