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: auto
bir 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 collapsed
CSS 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-bottom
0px'ten (genişletilmiş durumda) -2000px
daraltı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-bottom
Geçişi tek başına kullanmanın iki sorunu vardır:
- Aslında 2000 pikselden daha yüksek bir kutunuz varsa,
margin-bottom: -2000px
her ş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.3s
geçişle vererek çözeriz . Bu, aslında bir geçiş olmadığı, ancak max-height
gecikme ile uygulandığı anlamına gelir ; yalnızca geçiş bittiğinde geçerlidir. Bunun doğru çalışması max-height
iç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-height
asgari yükseklik geçişi için aslında kullanmamamızın sebebidir . Bunun yerine, ::after
kap içinde height
50 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 height
değ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-height
olduğunu güçlü daha max-height
Kullandığımız takdirde, bu kap var işe yaramaz min-height
yerine sözde eleman yıllarınheight
. Tıpkı max-height
önceki paragrafta bu max-height
da 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şletmekheight
istediğiniz alandan daha büyükse işe yarayacağına inanıyorum . Eğer bir varsamax-height
bir300px
ama dönebilirsiniz bir açılan kutu açılır,50px
daha sonramax-height
da 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şabilirheight
değil sabit,height:auto
çözüm, ama bununla geçişleri kullanamaz.