Pytanie Jak mogę zmienić wysokość: 0; do wysokości: auto; używając CSS?


Próbuję zrobić <ul> przesuń w dół za pomocą przejść CSS.

The <ul> zaczyna się od height: 0;. Po najechaniu wysokość jest ustawiona na height:auto;. Powoduje to jednak, że po prostu się pojawia, nie przejście,

Jeśli to zrobię height: 40px; do height: auto;, a następnie przesunie się do height: 0;, a następnie nagle przeskocz na odpowiednią wysokość.

Jak inaczej mogłem to zrobić bez użycia JavaScript?

#child0 {
  height: 0;
  overflow: hidden;
  background-color: #dedede;
  -moz-transition: height 1s ease;
  -webkit-transition: height 1s ease;
  -o-transition: height 1s ease;
  transition: height 1s ease;
}
#parent0:hover #child0 {
  height: auto;
}
#child40 {
  height: 40px;
  overflow: hidden;
  background-color: #dedede;
  -moz-transition: height 1s ease;
  -webkit-transition: height 1s ease;
  -o-transition: height 1s ease;
  transition: height 1s ease;
}
#parent40:hover #child40 {
  height: auto;
}
h1 {
  font-weight: bold;
}
The only difference between the two snippets of CSS is one has height: 0, the other height: 40.
<hr>
<div id="parent0">
  <h1>Hover me (height: 0)</h1>
  <div id="child0">Some content
    <br>Some content
    <br>Some content
    <br>Some content
    <br>Some content
    <br>Some content
    <br>
  </div>
</div>
<hr>
<div id="parent40">
  <h1>Hover me (height: 40)</h1>
  <div id="child40">Some content
    <br>Some content
    <br>Some content
    <br>Some content
    <br>Some content
    <br>Some content
    <br>
  </div>
</div>


1602
2017-08-18 02:50


pochodzenie


Wierzę w height:auto/max-height rozwiązanie zadziała tylko wtedy, gdy powiększasz obszar jest większy niż height chcesz ograniczyć. Jeśli masz max-height z 300px, ale rozwijane pole kombi, które może wrócić 50px, następnie max-height nie pomoże, 50px jest zmienna w zależności od liczby elementów, możesz dojść do niemożliwej sytuacji, w której nie mogę tego naprawić, ponieważ height nie jest naprawiony, height:auto było rozwiązaniem, ale nie mogę używać przejść z tym. - Christopher Thomas
OP próbuje rozwiązania css, nie js, w przeciwnym razie mogliby po prostu użyć przepełnienia i animacji - Toni Leigh
@ToniLeigh lub jQuery.slideToggle (); - mopo922
Wszystkie te odpowiedzi nie są całkiem "właściwe" ... Mam rozwiązanie (dodałem dziś odpowiedź) z tylko dwoma deklaracjami CSS. Nie używa ona maksymalnej wysokości. To czysty CSS i bardzo prosty w konfiguracji. Działa na względne pozycjonowanie. Oto skrzypce jsfiddle.net/n5XfG/2596 - VIDesignz
@VIDesignz: Ale wewnętrzny div -100% margin-top otrzymuje szerokość opakowania div, nie wysokość. To rozwiązanie ma ten sam rodzaj problemu, co rozwiązanie o maksymalnej wysokości. Ponadto, gdy szerokość jest mniejsza niż wysokość zawartości, nie cała zawartość jest ukryta w -100% margin-top. To niewłaściwe rozwiązanie. - GregTom


Odpowiedzi:


Posługiwać się max-height w transformacji, a nie height. I ustaw wartość na max-height do czegoś większego niż twoje pudełko kiedykolwiek dostaniesz.

Widzieć JSFiddle demo dostarczone przez Chrisa Jordana w innym odpowiedź tutaj.

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


2161
2017-11-30 18:42



to działa świetnie! z wyjątkiem opóźnienia, kiedy się zaczyna, ponieważ zaczyna się dla maksymalnej wysokości, która początkowo jest bardzo wysoka .. hmm, myślę, że to jest trochę irytujące - vsync
+1 Świetne rozwiązanie! Szybkość przejścia jest obliczana jako czas, w którym chcesz przejść do wartości maksymalnej wysokości ... ale ponieważ wysokość będzie mniejsza niż maksymalna wysokość, przejście do rzeczywistej wysokości nastąpi szybciej (często znacznie) niż określony czas. - kingjeffrey
Zauważ, że może to spowodować brzydkie zakończenie przejścia, gdy musisz użyć wartości, które są znacznie większe niż rzeczywista wartość obliczona. Zauważyłem to, starając się, aby element div wzrósł z wysokości 0 do wysokości zawartości, która różni się znacznie ze względu na różne rozmiary ekranu (2 linie na moim monitorze 2560x1440 względem> 10 linii na smartfonie). Do tego doszedłem do js. - jpeltoniemi
Świetna robota - nie rozwiązanie;) - acSlater
To całkiem leniwe rozwiązanie. Zakładam, że OP chce użyć height: auto, ponieważ rozszerzona wysokość kontenera jest nieco nieprzewidywalna. To rozwiązanie spowoduje opóźnienie, zanim animacja stanie się widoczna. Dodatkowo widoczny czas trwania animacji będzie nieprzewidywalny. Otrzymasz znacznie bardziej przewidywalne (i prawdopodobnie gładsze) wyniki, obliczając łączną wysokość każdego z węzłów kontenera, a następnie zmniejszając ją do dokładnej wartości wysokości. - Shawn Whinnery


Zamiast tego należy użyć scaleY.

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

Zrobiłem prefiksowaną wersję powyższego kodu od dostawcy na jsfiddle, http://jsfiddle.net/dotnetCarpenter/PhyQc/9/ i zmienił twoje jsfiddle, aby używać scaleY zamiast height, http://jsfiddle.net/dotnetCarpenter/7cnfc/206/.


228
2018-06-23 10:57



Aktualizuję tę odpowiedź, ponieważ działa ona dobrze w przeglądarkach obsługujących css3-transition, ale należy zauważyć, że w ogóle nie zadziała w IE <9, i nie będzie animowany (po prostu skacze) w IE <10 - Hailwood
Ta metoda tylko częściowo osiąga pożądany efekt, ale tak naprawdę nie działa usunąć przestrzeń. Przekształcone pudełko działa jak względnie umieszczony element - przestrzeń jest pobierana niezależnie od tego, jak jest skalowana. Sprawdzić to jsFiddle który zajmuje pierwszą i dodaje tylko fałszywy tekst na dole. Zwróć uwagę, że tekst pod nim nie przesuwa się w górę, gdy wysokość skrzynki zostanie wyskalowana do zera. - animuson♦
Teraz to robi: jsfiddle.net/gNDX3/1 Zasadniczo musisz stylizować elementy zgodnie z potrzebami. W CSS / HTML nie ma zachowań typu silver bullet lub widget. - dotnetCarpenter
Podczas gdy ja oklaskuję kogoś próbującego różne podejścia, rzeczywisty efekt i komplikacje, jakie przynosi to rozwiązanie, są o wiele gorsze niż i tak już straszny hack o maksymalnej wysokości. Proszę nie używać. - mystrdat
Odstępy nieudane jsfiddle.net/PhyQc/336 - e-info128


Nie możesz obecnie animować na wysokości, gdy jedna z wysokości jest zaangażowana auto, musisz ustawić dwie wyraźne wysokości.


164
2017-08-18 12:46



Zwykle istnieje wiele sposobów rozwiązania problemu, a nie wszystkie są odpowiednie lub możliwe. Nie wiem, dlaczego @JedidiahHurt i Ryan Ore próbują ograniczyć możliwe odpowiedzi na stronie pytań i odpowiedzi. Szczególnie biorąc pod uwagę, że ta odpowiedź była tutaj pierwsza. Tak więc, ponieważ przyjęta odpowiedź jest obejściem. - Hooray Im Helping
Odpowiedź od @jake nie jest ani elegancka, ani poprawna. Połączona odpowiedź jest o wiele lepsza. Działa poprawnie i obsługuje wszystkie wielkości - nie można powiedzieć o zaakceptowanej odpowiedzi. - GraphicsMuncher
Czy to się zmieniło? W bootstrapie mniej dla zawalenia widzę, że wyraźnie zmieniają wysokość i o ile wiem, dostosowują się do dowolnej wysokości: .collapsing { position: relative; height: 0; overflow: hidden; .transition-property(~"height, visibility"); .transition-duration(.35s); .transition-timing-function(ease); } - Andy
Och, no wiesz, założę się, że bootstrap po prostu wylicza i ustawia wysokość zawartości tuż przed uruchomieniem animacji CSS ... - Andy
Tak: tak this.$element[dimension](this.$element[dimension]())[0].offsetHeight - Andy


Rozwiązaniem, które zawsze stosowałem, było najpierw zanikać, a następnie zmniejszać font-size, padding i margin wartości. Nie wygląda tak jak wytarcie, ale działa bez zakłóceń height lub max-height.

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

Przykład roboczy:

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

Spacing.


81
2018-05-29 14:05



Dobrze mi się układało. Nie całkiem jak jQuery slideUp / Down. Różnicę widać tylko w przypadku słabych procesorów, takich jak stare komputery lub urządzenia przenośne, oraz otwierania i zamykania wielu z nich w tym samym czasie. - Cruz Nunez
Jeśli masz przyciski lub inne elementy nie będące tekstem, otrzymasz niechciane spacje bez zawieszania się. - Dennis W
Możesz dalej udoskonalić, wybierając wszystkie elementy podrzędne za pomocą * i stosowanie innych zmian. Jednak powyższy kod powinien wpłynąć na przyciski, jednak jeśli były one poprawnie ustawione em. - Steven Vachon
W moim przypadku musiałem też dodać line-height: 0; i border-width: 0; - Andrey Shatilov
Nie musisz dostosowywać line-height jeśli prawidłowo unikasz jednostek na wartości: developer.mozilla.org/en-US/docs/Web/CSS/... - Steven Vachon


Możesz, przy odrobinie nie-semantycznej manipulacji jiggery. Moim typowym podejściem jest animacja wysokości zewnętrznego DIV, który ma jedno dziecko, które jest DIV bez stylu, używanym tylko do pomiaru wysokości treści.

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>

Chciałoby się po prostu móc zrezygnować z .measuringWrapper i po prostu ustaw wysokość DIV na auto i animuj to, ale to nie działa (wysokość zostaje ustawiona, ale animacja nie występuje).

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>

Moją interpretacją jest to, że do uruchomienia animacji potrzebna jest wyraźna wysokość. Nie można uzyskać animacji na wysokości, gdy wysokość (wysokość początkowa lub końcowa) jest auto.


64
2018-06-30 13:32



Ponieważ jest to zależne od javascript, możesz również łatwo dodać MeasureWrapper używając javascript też! - Quickredfox
Możesz to zrobić bez opakowania. Po prostu: function growDiv () {var growDiv = document.getElementById ('grow'); if (growDiv.clientHeight) {growDiv.style.height = 0; } else {growDiv.style.height = growDiv.scrollHeight + 'px'; }} - user1742529
Sprawdź to ... porozmawiaj o prostej odpowiedzi jsfiddle.net/n5XfG/2596 ... Twoja odpowiedź jest szalenie skomplikowana bez żadnego powodu. Nie ma potrzeby max-height, nie ma potrzeby auto, a zwłaszcza nie ma potrzeby Javascript! Tylko dwie proste deklaracje - VIDesignz
@VIDesignz Ożywiasz nadwyżkę: 100%. To jest 100% wartości szerokość elementu, a nie jego wysokość! Oznacza to, że jeśli masz element o wysokości większej niż jego szerokość, to go nie ukryje. Ponadto rzeczywisty prędkość animacji jest zupełnie inna niż zdefiniowana. - Timo Türschmann
Byłem podekscytowany odpowiedzią VIDesignza, dopóki nie przeczytałem więcej o komentarzu Timo. Tak, margin-top (i margin-bottom) są względne do szerokości, gdy są zdefiniowane w procentach, tak, to jest głupie, ale wyjaśnia również, dlaczego czasy otwarcia i zamknięcia animacji są zupełnie inne - to to samo, co widać w najlepiej ocenianej odpowiedzi, określając zakodowany maksymalny wysokość. Dlaczego tak trudno to zrobić? - Coderer


Wiem, że jest to trzydziestoparametrowa odpowiedź na to pytanie, ale myślę, że warto, więc tu idzie. To jest Tylko CSS rozwiązanie o następujących właściwościach:

  • Na początku nie ma opóźnień, a przejście nie zatrzymuje się wcześniej. W obu kierunkach (rozwijanie i zwijanie), jeśli określisz czas przejścia na 300 ms w swoim CSS, to przejście zajmie 300 ms, kropka.
  • Przejmuje rzeczywistą wysokość (w przeciwieństwie do transform: scaleY(0)), więc robi to dobrze, jeśli zawartość zawiera element zwijany.
  • Podczas gdy (podobnie jak w innych rozwiązaniach) istnieje  magiczne liczby (jak "wybierz długość, która jest wyższa niż twoje pudełko, będzie"), to nie jest śmiertelne, jeśli twoje założenie kończy się błędem. Przejście może nie wyglądać w tym przypadku niesamowicie, ale przed i po przejściu nie stanowi to problemu: W rozwiniętym (height: auto) stwierdza, że ​​cała zawartość ma zawsze odpowiednią wysokość (w przeciwieństwie do np. wyboru max-heightktóry okazuje się być zbyt niski). W stanie zwiniętym wysokość wynosi zero, tak jak powinna.

Próbny

Oto demo z trzema składanymi elementami, o różnych wysokościach, z których wszystkie używają tego samego CSS. Możesz kliknąć "całą stronę" po kliknięciu "run snippet". Zauważ, że JavaScript tylko przełącza collapsed Klasa CSS, nie ma żadnego pomiaru. (Możesz zrobić to dokładnie w wersji demo bez żadnego JavaScriptu, używając pola wyboru lub :target). Zauważ również, że część CSS odpowiedzialna za przejście jest dość krótka, a kod HTML wymaga tylko jednego dodatkowego elementu opakowania.

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

Jak to działa?

W rzeczywistości dwa przejścia zaangażowane w to. Jeden z nich przechodzi w margin-bottom od 0px (w stanie rozwiniętym) do -2000px w stanie zwiniętym (podobnym do ta odpowiedź). 2000 to pierwsza liczba magiczna, opiera się na założeniu, że twoje pudełko nie będzie wyższe (2000 pikseli wydaje się rozsądnym wyborem).

Używając margin-bottom sama transformacja ma dwie kwestie:

  • Jeśli rzeczywiście masz pudełko, które ma ponad 2000 pikseli, to a margin-bottom: -2000px nie ukryją wszystkiego - będą widoczne rzeczy nawet w zawalonej skrzynce. To drobna poprawka, którą zrobimy później.
  • Jeśli rzeczywiste pole ma, powiedzmy, 1000 pikseli wysokości, a przejście ma długość 300ms, a następnie widoczny przejście jest już zakończone po około 150 ms (lub, w przeciwnym kierunku, rozpoczyna 150ms z opóźnieniem).

Naprawa tego drugiego problemu pojawia się w miejscu, w którym pojawia się drugie przejście, a to przejście jest konceptualnie ukierunkowane na opakowanie minimum wysokość ("koncepcyjnie", ponieważ tak naprawdę nie używamy min-height właściwość do tego; więcej o tym później).

Oto animacja pokazująca, w jaki sposób połączenie przejścia dolnego marginesu z minimalnym przejściem wysokości, oba o równym czasie trwania, daje nam połączone przejście z pełnej wysokości do zera wysokości, które ma ten sam czas trwania.

animation as described above

Lewy pasek pokazuje, w jaki sposób ujemny margines dolny przesuwa dno w górę, zmniejszając widoczną wysokość. Środkowy pasek pokazuje, w jaki sposób minimalna wysokość zapewnia, że ​​w przypadku zwijania przejście nie zakończy się wcześniej, aw przypadku rozwijania przejście nie rozpocznie się zbyt późno. Prawy pasek pokazuje, w jaki sposób połączenie tych dwóch elementów powoduje przejście pudełka od pełnej wysokości do zera wysokości w prawidłowym czasie.

Dla mojej wersji demo ustawiłem 50px jako górną minimalną wartość wysokości. Jest to druga liczba magiczna, która powinna być niższa niż wysokość pudełka. 50px również wydaje się rozsądne; wydaje się mało prawdopodobne, że bardzo często chciałbyś zrobić element składany, który nie ma nawet 50 pikseli wysokości.

Jak widać w animacji, wynikowe przejście jest ciągłe, ale nie jest różniczkowalne - w momencie, gdy minimalna wysokość jest równa pełnej wysokości dostosowanej przez dolny margines, następuje nagła zmiana prędkości. Jest to bardzo zauważalne w animacji, ponieważ wykorzystuje funkcję liniowego taktowania dla obu przejść, a także dlatego, że całe przejście jest bardzo powolne. W rzeczywistym przypadku (moje demo u góry) przejście trwa tylko 300ms, a przejście do dolnej krawędzi nie jest liniowe. Grałem z wieloma różnymi funkcjami czasowymi dla obu przejść, a te, z których wylądowałem sprawiały, że działały najlepiej w najróżniejszych przypadkach.

Pozostają dwa problemy do rozwiązania:

  1. punkt z góry, w którym pola o wysokości przekraczającej 2000 pikseli nie są całkowicie ukryte w stanie zwiniętym,
  2. i odwrotny problem, gdzie w niewidocznym przypadku skrzynie o wysokości mniejszej niż 50 pikseli są zbyt wysokie, nawet jeśli przejście nie jest uruchomione, ponieważ minimalna wysokość utrzymuje je na poziomie 50 pikseli.

Rozwiązujemy pierwszy problem, podając element pojemnika a max-height: 0 w zwiniętym przypadku, z a 0s 0.3s przejście. Oznacza to, że tak naprawdę nie jest to przejście, ale max-height jest stosowany z opóźnieniem; ma zastosowanie tylko po zakończeniu przejścia. Aby to działało poprawnie, musimy również wybrać numeryczne max-height dla przeciwnego stanu, bez załamania. Ale w odróżnieniu od przypadku 2000px, gdy zbieranie zbyt dużej liczby wpływa na jakość przejścia, w tym przypadku tak naprawdę nie ma znaczenia. Możemy więc wybrać liczbę, która jest tak wysoka, że ​​my wiedzieć że żadna wysokość nigdy się do tego nie zbliży. Wybrałem milion pikseli. Jeśli uważasz, że możesz potrzebować obsługi treści o wysokości ponad miliona pikseli, to 1) Przykro mi, i 2) po prostu dodaj kilka zer.

Drugi problem jest powodem, dla którego w rzeczywistości nie używamy min-height dla minimalnej zmiany wysokości. Zamiast tego istnieje ::after pseudoelement w kontenerze z height która zmienia się z 50px na zero. Ma to taki sam skutek jak min-height: Nie pozwoli, aby kontener skurczył się poniżej jakiejkolwiek wysokości, jaką ma obecnie pseudoelement. Ale ponieważ używamy height, nie min-height, możemy teraz użyć max-height (ponownie zastosowane z opóźnieniem), aby ustawić rzeczywistą wysokość pseudoelementu na zero po zakończeniu przejścia, zapewniając, że przynajmniej poza przejściem, nawet małe elementy mają odpowiednią wysokość. Bo min-height jest silniejszy niż max-height, to nie zadziała, jeśli użyjemy kontenera min-height zamiast pseudoelementu height. Podobnie jak max-height w poprzednim akapicie to max-height również potrzebuje wartości dla przeciwnego końca przejścia. Ale w tym przypadku możemy wybrać 50px.

Testowane w Chrome (Win, Mac, Android, iOS), Firefox (Win, Mac, Android), Edge, IE11 (z wyjątkiem problemów z układem flexbox z moim demo, które nie przeszkadzały mi w debugowaniu) i Safari (Mac, iOS ). Mówiąc o flexbox, powinno być możliwe wykonanie tej pracy bez użycia jakiegokolwiek flexbox; w rzeczywistości wydaje mi się, że w IE7 można wykonać prawie wszystko - oprócz tego, że nie będziesz miał przejść CSS, co sprawi, że będzie to raczej bezcelowe ćwiczenie.


45
2018-05-14 14:33



Chciałbym, abyś mógł skrócić (uprościć) swoje rozwiązanie, lub przynajmniej przykład kodu - wygląda na to, że 90% przykładowego kodu nie ma znaczenia dla twojej odpowiedzi. - Gil Epshtain


Wizualnym obejściem animacji wysokości za pomocą przejść CSS3 jest animowanie dopełnienia.

Nie uzyskujesz pełnego efektu wycierania, ale granie z wartościami czasu trwania przejścia i dopełnienia powinno zapewnić Ci wystarczająco blisko. Jeśli nie chcesz jawnie ustawiać wysokości / maks. Wysokości, to powinno być to, czego szukasz.

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/ (riffed off stephband powyżej jsFiddle)


44
2018-06-26 19:05



Myślę, że to najlepsza odpowiedź. Ta technika może również rozciągać się w celu dopasowania dopełnienia do dzieci. W moim przypadku udało mi się połączyć to z wyraźnymi przejściami wysokościowymi na niektórych z ujawnianych treści, a całkowity efekt jest o wiele bardziej skuteczny niż praca z maksymalną wysokością, co jest dobre dla odsłonięcia, ale wprowadza niezręczny moment opóźnienie w ukryciu. Wolałbym nie animować, niż wprowadzić bezsensowne opóźnienie, które sprawia, że ​​moja aplikacja wydaje się nie odpowiadać. Jestem zaskoczony, że wielu ludzi uważa, że ​​jest to do przyjęcia. - Semicolon
Tyle że tutaj wcale nie animujesz wysokości. Animujesz wypełnienie ... może zniknąć, ponieważ może animować od bieżącego stanu do zera, ale jeśli uważnie przyglądasz się, gdy się rozwija, otwiera się z tekstem, a następnie dopełnienie animuje tylko ... ponieważ nie Wiesz jak animować od 0 do auto .... potrzebuje zakresu liczbowego ... tak działa twenting. - Rob R
To jest dobre obejście, które nie jest hacky. To nie jest najlepsza odpowiedź to pytanie, ale jest to alternatywa, która sprawdziła się u mnie. Czasem potrzebujesz efektu animacji wysokości, a nie pełnej animacji :) - Ivan Durst
To rozwiązanie również nie działa, gdy używane jest opóźnienie przejścia. - Michel Joanisse
Zgadzam się także, że to rozwiązanie jest czystym obejściem, które zapewnia dość płynne przejścia, jeśli twoja animacja jest wystarczająco szybka (w moim przypadku na akordeon z przejściami 0.1s jest idealny!). Nie będzie to jednak wiele aplikacji, ale inni ankieterzy na to pytanie również nie będą! - Remi D


Moje obejście polega na przeniesieniu maksymalnej wysokości do dokładnej wysokości treści w celu uzyskania ładnej płynnej animacji, a następnie skorzystania z wywołania zwrotnego transitionEnd w celu ustawienia maksymalnej wysokości na 9999px, aby zawartość mogła swobodnie zmieniać rozmiar.

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>


43
2018-03-19 00:44



@ Derija93 Używa to zwykłych starych animacji czasu javascript. Wyzwaniem jest użycie przejść CSS3. - Adam
No tak. Ale dlaczego używałbyś "przejść CSS3 zamiast", jeśli w twoim przykładzie używasz już jQuery, biblioteki, która zapewnia dużo "zapisz mniej, zrób więcej", mimo to? Chciałem podkreślić, że twoja wersja może wyglądać o wiele lepiej, nawet jeśli jest bardziej skomplikowana, jeśli NIE używa jQuery, aby mogła działać praktycznie na dowolnej stronie. Sądzę, że źle to sformułowałem. Przepraszam za to. ;) - Kiruse
@ Derija93 Być może dlatego, że przejścia CSS3 mają (według wszystkich źródeł mogę znaleźć) znacznie lepszą wydajność niż animacje jQuery. (Właściwie ma to ogromne znaczenie dla mojego obecnego przypadku użycia, który przywiódł mnie tutaj.) - Mark Amery
@ Derija93 'Ponieważ animacje Javascript działają powoli w porównaniu do przejść CSS3, a przy animacjach jQuery musisz się martwić o pętlę animacji. Animuj coś na kliknięcie, a następnie szybko kliknij i obserwuj, jak animacje powtarzają się. Jest to obsługiwane za pomocą CSS3. - Dropped.on.Caprica
@ Dropped.on.Caprica To jest trochę stare. Powiedziałem już, że źle zrozumiałem koncepcję, którą próbował zademonstrować. W każdym razie, dla prostych animacji, .stop robi sztuczkę dla dość skomplikowanego problemu z pętlą animacji. Teraz, gdy animujesz wysokość i kolor, ale chcesz tylko przerwać animację wysokości, rzeczy stają się trochę trudniejsze ... Dostaję twój punkt widzenia. - Kiruse