Bunun bu sorunun otuz bir yanıtı olduğunu biliyorum, ama bence buna değer, işte gidiyor. Bu, aşağıdaki özelliklere sahip yalnızca CSS çözümdür:
- Başlangıçta gecikme olmaz ve geçiş erken durmaz. Her iki yönde de (genişleme ve daralma), CSS'nizde 300 ms'lik bir geçiş süresi belirtirseniz, geçiş 300 msn sürer.
- Gerçek yüksekliği değiştirir (aksine
transform: scaleY(0)), bu nedenle daraltılabilir öğeden sonra içerik varsa doğru olanı yapar.
- (Diğer çözümlere olduğu gibi) Oradayken olan sihirli sayılar ise (gibi "Kutun hiç olacak daha yüksek bir uzunluğa almak"), bu öldürücü değil yanlış olduğunu belirten yukarı varsayım biter. Geçiş bu durumda şaşırtıcı görünmeyebilir, ancak önce ve geçişten sonra, bu bir sorun değildir: Genişletilmiş (In
height: autobir seçim varsa) devlet, tüm içerik her zaman (aksine örneğin doğru yüksekliğe sahip max-heightçıkıyor bu olmak çok düşük). Ve çökmüş durumda, yükseklik olması gerektiği gibi sıfırdır.
gösteri
İşte hepsi aynı CSS'yi kullanan, farklı yüksekliklerde üç katlanabilir öğeye sahip bir demo. "Snippet'i çalıştır" ı tıkladıktan sonra "tam sayfa" yı tıklamak isteyebilirsiniz. JavaScript'in yalnızca collapsedCSS sınıfını değiştirdiğini, ölçüm yapılmadığını unutmayın. (Bu tam demosu herhangi bir JavaScript olmadan bir onay kutusu veya kullanarak yapabilirsiniz :target). Ayrıca, CSS'nin geçişten sorumlu bölümünün oldukça kısa olduğunu ve HTML'nin yalnızca tek bir ek sarma öğesi gerektirdiğini unutmayın.
$(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>
O nasıl çalışır?
Aslında bunun gerçekleşmesi için iki geçiş söz konusudur. Bunlardan biri margin-bottom0px'ten (genişletilmiş durumda) -2000pxdaraltılmış duruma ( bu cevaba benzer ) geçer. Buradaki ilk sihirli sayı 2000, kutunuzun bundan daha yüksek olmayacağı varsayımına dayanıyor (2000 piksel makul bir seçim gibi görünüyor).
margin-bottomGeçişi tek başına kullanmanın iki sorunu vardır:
- Aslında 2000 pikselden daha yüksek bir kutunuz varsa,
margin-bottom: -2000pxher şeyi gizlemezsiniz - daraltılmış durumda bile görünür şeyler olacak. Bu, daha sonra yapacağımız küçük bir düzeltmedir.
- Gerçek kutu, örneğin, 1000 piksel yüksekliğinde ve geçişiniz 300ms uzunluğundaysa, görünür geçiş yaklaşık 150ms'den sonra biter (veya ters yönde 150ms geç başlar).
Bu ikinci sorunu düzeltmek, ikinci geçişin geldiği yerdir ve bu geçiş kavramsal olarak sargının minimum yüksekliğini hedefler ("kavramsal olarak" çünkü aslında bunun için min-heightözelliği kullanmıyoruz ; daha sonra bu).
Alt kenar geçişini, her ikisi de eşit süreli minimum yükseklik geçişiyle birleştirmenin, bize tam yükseklikten sıfır yüksekliğe aynı süreye sahip kombine geçişi nasıl verdiğini gösteren bir animasyon.

Sol çubuk, negatif alt kenar boşluğunun alt kısmı nasıl yukarı doğru ittiğini gösterir ve görünür yüksekliği azaltır. Orta çubuk, minimum yüksekliğin çöken durumda geçişin erken bitmemesini ve genişleyen durumda geçişin geç başlamamasını nasıl sağladığını gösterir. Sağ çubuk, ikisinin kombinasyonunun, kutunun tam yükseklikten sıfır yüksekliğe doğru sürede nasıl geçişine neden olduğunu gösterir.
Demo için en yüksek minimum yükseklik değeri olarak 50 piksele yerleştim. Bu ikinci sihirli sayıdır ve kutunun yüksekliğinden daha düşük olmalıdır. 50 piksel de makul görünüyor; en başta 50 piksel yüksekliğinde olmayan bir öğeyi katlanabilir hale getirmek istemeniz pek olası görünmüyor.
Animasyonda görebileceğiniz gibi, ortaya çıkan geçiş süreklidir, ancak ayırt edilemez - minimum yüksekliğin alt kenar boşluğu tarafından ayarlanan tam yüksekliğe eşit olduğu anda, hızda ani bir değişiklik olur. Bu, animasyonda çok dikkat çekicidir, çünkü her iki geçiş için doğrusal bir zamanlama işlevi kullanır ve tüm geçiş çok yavaştır. Gerçek durumda (üstteki demom), geçiş sadece 300 ms sürer ve alt kenar boşluğu geçişi doğrusal değildir. Her iki geçiş için de birçok farklı zamanlama fonksiyonu ile oynadım ve sonlandıklarım en geniş çeşitlilikte en iyi şekilde çalıştıklarını hissettim.
Çözülmesi gereken iki sorun var:
- yukarıdan nokta, 2000 pikselden daha yüksek yükseklikteki kutuların daraltılmış durumda tamamen gizlenmediği,
- ve gizli olmayan durumda, geçiş çalışmadığında bile 50 piksel yüksekliğinden daha az olan kutuların çok yüksek olduğu ters sorun, çünkü minimum yükseklik onları 50 pikselde tutar.
İlk sorunu max-height: 0, çökmüş durumda konteyner elemanına bir 0s 0.3sgeçişle vererek çözeriz . Bu, aslında bir geçiş olmadığı, ancak max-heightgecikme ile uygulandığı anlamına gelir ; yalnızca geçiş bittiğinde geçerlidir. Bunun doğru çalışması max-heightiçin, ters, daraltılmamış durum için bir sayısal seçmemiz gerekir . Ancak, çok büyük bir sayı seçmenin geçişin kalitesini etkilediği 2000 piksel durumundan farklı olarak, bu durumda, gerçekten önemli değil. Bu yüzden sadece bu yüzden yüksek biz bir sayı seçebilirsiniz biliyorum hiçbir yükseklik şimdiye kadar bu yakın gelecek. Bir milyon piksel seçtim. Bir milyon pikselden daha yüksek bir yüksekliği desteklemeniz gerekebileceğini düşünüyorsanız, 1) Üzgünüm ve 2) sadece birkaç sıfır ekleyin.
İkinci sorun, min-heightasgari yükseklik geçişi için aslında kullanmamamızın sebebidir . Bunun yerine, ::afterkap içinde height50 pikselden sıfıra geçiş yapan bir sözde öğe vardır . Bu, aşağıdakilerle aynı etkiye sahiptir min-height: Konteynerin şu anda sözde elemanın sahip olduğu yüksekliğin altına düşmesine izin vermez. Ancak, kullandığımız için heightdeğil min-height, şimdi geçiş max-height(bir kez daha gecikmeli olarak uygulandı) kullanarak geçiş elemanının gerçek yüksekliğini geçiş bittiğinde sıfıra ayarlamak için kullanabiliriz, en azından geçişin dışında, hatta küçük elemanların doğru yükseklik. Çünkü min-heightolduğunu güçlü daha max-heightKullandığımız takdirde, bu kap var işe yaramaz min-heightyerine sözde eleman yıllarınheight. Tıpkı max-heightönceki paragrafta bu max-heightda geçişin diğer ucunda için bir değer gerekiyor. Ancak bu durumda 50 pikseli seçebiliriz.
Chrome (Win, Mac, Android, iOS), Firefox (Win, Mac, Android), Edge, IE11 (hata ayıklamayı rahatsız etmediğim demomla ilgili bir flexbox düzen sorunu hariç) ve Safari'de (Mac, iOS) test edildi ). Flexbox'tan bahsetmişken, bu işi herhangi bir flexbox kullanmadan yapmak mümkün olmalıdır; Aslında, IESS'de neredeyse her şeyi çalıştırabileceğinizi düşünüyorum - CSS geçişleri olmayacak, onu oldukça anlamsız bir egzersiz haline getirebilirsiniz.
height:auto/max-heightÇözümün ancak alanı genişletmekheightistediğiniz alandan daha büyükse işe yarayacağına inanıyorum . Eğer bir varsamax-heightbir300pxama dönebilirsiniz bir açılan kutu açılır,50pxdaha sonramax-heightda yardım etmiyor,50pxçünkü elemanlarının sayısına bağlı olarak değişkendir, sen bunu düzeltemez imkansız bir duruma ulaşabilirheightdeğil sabit,height:autoçözüm, ama bununla geçişleri kullanamaz.