Yüksekliği nasıl değiştirebilirim: 0; yükseklik: otomatik; CSS mi kullanıyorsunuz?


2134

<ul>CSS geçişlerini kullanarak bir slayt aşağı yapmaya çalışıyorum .

<ul>En başlıyor height: 0;. Fareyle üzerine gelindiğinde yükseklik olarak ayarlanır height:auto;. Ancak bu, geçiş değil , görünmesine neden oluyor ,

Eğer 'den' height: 40px;e doğru yaparsam height: auto;, o zaman yukarı kayar height: 0;ve sonra aniden doğru yüksekliğe atlar.

JavaScript kullanmadan bunu başka nasıl yapabilirim?

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


height:auto/max-heightÇözümün ancak alanı genişletmek heightistediğiniz alandan daha büyükse işe yarayacağına inanıyorum . Eğer bir varsa max-heightbir 300pxama dönebilirsiniz bir açılan kutu açılır, 50pxdaha sonra max-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şabilir heightdeğil sabit, height:autoçözüm, ama bununla geçişleri kullanamaz.
Christopher Thomas

51
OP js için değil css çözümü için çalışıyor, aksi takdirde sadece taşma ve animasyon kullanabilirsiniz
Toni Leigh

5
@VIDesignz: Ancak iç div'ın% -100 marj üstü , yüksekliği değil sarıcı div'in genişliğini alır . Yani bu çözüm aynı yüksekliğe sahip, maksimum yükseklik çözümü. Ayrıca, genişlik içeriğin yüksekliğinden daha küçük olduğunda, tüm içerik% -100 marj üstü ile gizlenmez. Yani bu yanlış bir çözüm.
GregTom

1
Uygun bir çözümün özellikleri ve uygulanması hakkında tartışma için github.com/w3c/csswg-drafts/issues/626 adresine bakın
Ben Creasy

Yanıtlar:


2745

Geçişte kullanın max-height, değil height. Ve max-heightkutunuzun alacağından daha büyük bir şeye değer verin.

Bkz JSFiddle demo başka Chris Jordan tarafından sağlanan cevap burada.

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


323
bu harika çalışıyor! başlangıçta çok yüksek olan maksimum yükseklik için başladığı için başladığında bir gecikme hariç .. hmm, bu biraz sinir bozucu olduğunu düşünüyorum
vsync

175
+1 Mükemmel çözüm! Geçiş hızı hesaplanır, maksimum yükseklik değerine geçiş için belirttiğiniz süre olarak hesaplanır ... ancak yükseklik maksimum yükseklikten daha az olacağından, gerçek yüksekliğe geçiş daha hızlı (genellikle önemli ölçüde) gerçekleşir. zaman belirtildi.
kingjeffrey

50
Gerçek hesaplanan değerden çok daha büyük değerler kullanmanız gerektiğinde bunun çirkin bir geçiş sonlanmasına neden olabileceğini unutmayın. Bir divın 0 yükseklikten farklı ekran boyutları nedeniyle büyük ölçüde değişen içerik yüksekliğine büyümeye çalıştığını fark ettim (2560x1440 monitörümdeki 2 satır vs bir akıllı telefondaki> 10 satır). Bunun için js ile sona erdi.
jpeltoniemi

44
Çok çirkin çözüm çünkü bir yönde bir gecikme yaratır, diğerinde değil.
Tim

84
Bu oldukça tembel bir çözüm. OP'nin height: auto kullanmak istediğini varsayıyorum çünkü konteynerin genişletilmiş yüksekliği biraz tahmin edilemez. Bu çözüm, animasyon görünür olmadan önce gecikmeye neden olur. Ek olarak, animasyonun görünür süresi önceden kestirilemez. Kapsayıcı alt düğümlerinin her birinin birleşik yüksekliğini hesaplayıp daha sonra kesin bir yükseklik değerine gevşeterek çok daha tahmin edilebilir (ve muhtemelen daha pürüzsüz) sonuçlar elde edersiniz.
Shawn Whinnery

314

Bunun yerine scaleY'yi kullanmalısınız.

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>

Ben yukarıdaki kod jsfiddle bir satıcı önekli sürümünü yaptım ve jsfiddle yükseklik yerine scaleY kullanmak için değiştirdim .


6
O css3-geçiş yapabilen tarayıcılarda iyi çalışır çünkü bu cevabı upvoting ediyorum, ama bu unutulmamalıdır IE <9'da hiç çalışmaz ve <IE (sadece atlayacaktır) animasyon alışkanlık 10
Hailwood

215
Bu yöntem sadece istenen etkiyi kısmen elde eder, ancak aslında alanı kaldırmaz . Dönüştürülen kutu nispeten konumlandırılmış bir eleman gibi davranır - nasıl ölçeklendirilirse kullanılsın, alan kaplanır. İlkini alan ve altta sahte metin ekleyen bu jsFiddle'a göz atın. Kutu yüksekliği sıfıra ölçeklendiğinde altındaki metnin nasıl hareket etmediğine dikkat edin.
animuson

9
Şimdi yapar: jsfiddle.net/gNDX3/1 Temel olarak öğelerinizi ihtiyacınız olana göre şekillendirmeniz gerekir. CSS / HTML'de gümüş kurşun veya widget benzeri davranış yoktur.
dotnetCarpenter

70
Farklı yaklaşımlar deneyen birini alkışlarken, bu çözümün getirdiği gerçek dünya etkisi ve komplikasyonları zaten korkunç maksimum yükseklik hackinden çok daha kötü. Lütfen kullanmayın.
mystrdat

2
@SquareCat tamam tamam. İşte daha fazla çekmece olan: jsfiddle.net/dotnetCarpenter/WTL2r
dotnetCarpenter

202

Şu anda ilgili yüksekliklerden biri olduğu zaman yükseklik üzerinde animasyon yapamazsınız auto, iki açık yükseklik ayarlamanız gerekir.


12
Bir sorunu çözmenin genellikle birden fazla yolu vardır ve bunların hepsi uygun veya mümkün değildir. @JedidiahHurt ve Ryan Ore'nin bir soru-cevap sitesinde olası cevapları neden sınırlandırmaya çalıştıklarını bilmiyorum. Özellikle bu cevabı dikkate alarak ilk önce buradayız. Şüphesiz, kabul edilen cevap bir çözüm olduğundan.
Yaşasın

5
@ Jake'in cevabı ne zarif ne de doğru. Buradaki bağlantılı cevap çok daha iyi. Doğru şekilde çalışır ve tüm boyut vakalarını işler - kabul edilen cevaptan ikisi söylenemez.
GraphicsMuncher

5
Evet: öylethis.$element[dimension](this.$element[dimension]())[0].offsetHeight
Andy

4
Bunun bir şekilde düzeltilmesi planlanıyor mu? Yani, bu 0 yükseklikten geçiş yapabilmeyi beklemek oldukça doğal auto...
Augustin Riedinger

6
@Meliodas "hayır / yapamazsınız" Stack Overflow ile ilgili sorulara geçerli ve kabul edilebilir bir cevaptır.
TylerH

122

Hep kullanmış olduğunuz çözeltisi daha sonra küçültmek, ilk solma out oldu font-size, paddingve margindeğerleri. Bir mendil ile aynı görünmez, ancak statik heightveya olmadan çalışır max-height.

Çalışma örneği:

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


Benim için düzgün çalıştı. JQuery slideUp / Down gibi değil. Yalnızca eski bilgisayarlar veya mobil cihazlar gibi zayıf CPU'larla ve aynı anda birçoğunu açıp kapatarak bir fark görebilirsiniz.
Cruz Nunez

3
Düğmeleriniz veya metin olmayan herhangi bir öğeniz varsa, havada asılı kalmadan istenmeyen boşluklarla karşılaşırsınız.
Dennis W

3
Tüm alt öğeleri seçerek *ve diğer değişiklikleri uygulayarak daha da hassaslaştırabilirsiniz . Bununla birlikte, doğru şekilde stilize edilmişlerse düğmeler yukarıdaki kodumdan etkilenmiş olmalıydı em.
Steven Vachon

1
Benim durumumda, ben de eklemem gerekiyordu line-height: 0;veborder-width: 0;
Andrey Shatilov

1
line-height
Değerdeki

93

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.

yukarıda açıklandığı gibi 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:

  1. yukarıdan nokta, 2000 pikselden daha yüksek yükseklikteki kutuların daraltılmış durumda tamamen gizlenmediği,
  2. 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.


35
Keşke çözümünüzü kısaltmak (basitleştirmek) ya da en azından kod örneği - kod örneğinin% 90'ı cevabınızla ilgili değil gibi görünüyor.
Gil Epshtain

Eğer collapsible-wrappermutlak bir pozisyonu varsa, bu geçişleri de çalıştırmanın bir yolu var mı ? overflow: hiddenAna kesinlikle konumlandırılır elemanları ile geçiş ancak parazitlerden için gereklidir.
pmkro

1
@pmkro Evet, ben de bu problemi yaşadım. Bir clip-path: polygon(...)yerine kullanarak overflow: hiddençözdüm, çünkü ikincisinin aksine, öncekine geçiş yapabilirsiniz. Eski tarayıcılar için bir yedek olarak ek bir ölçeklendirme dönüşümü kullandım. Github.com/StackExchange/Stacks/blob/develop/lib/css/components/…
balpha'nın

2
Güzel. Bu gerçekten iyi çalışıyor. Kabul edilen cevap olmalı
Henry Ing-Simmons

84

Biraz anlamsal olmayan jiggery-pokery ile yapabilirsiniz. Her zamanki yaklaşımım, yalnızca içerik yüksekliğini ölçmek için kullanılan, stilsiz bir DIV olan tek bir çocuğu olan bir dış DIV'nin yüksekliğini canlandırmaktır.

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>

Biri .measuringWrappersadece DIV'nin yüksekliğini otomatik olarak ayarlayabilir ve bu canlandırmaya sahip olabilir, ancak bu işe yaramaz gibi görünür (yükseklik ayarlanır, ancak animasyon gerçekleşmez).

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>

Benim yorumum, animasyonun çalışması için açık bir yüksekliğe ihtiyaç olduğudur. Yükseklik (başlangıç ​​veya bitiş yüksekliği) her iki yükseklikte de bir animasyon alamazsınız auto.


10
Bu javascript dayanıyor, ayrıca javascript kullanarak MeasurementWrapper kolayca ekleyebilirsiniz!
Quickredfox

18
Sarıcı olmadan yapabilirsiniz. Sadece: function growDiv () {var growDiv = document.getElementById ('grow'); if (growDiv.clientHeight) {growDiv.style.height = 0; } else {growDiv.style.height = growDiv.scrollHeight + 'px'; }}
user1742529

8
Şuna bir bak ... basit bir cevap hakkında konuş jsfiddle.net/n5XfG/2596 ... Cevabınız iyi bir sebep olmadan delicesine karmaşık. Gerek yok, gerek max-heightyok autove özellikle Javascript gerek yok !! Sadece iki basit bildirim
VIDesignz

12
@VIDesignz Marjın üzerinde canlandırıyorsunuz:% 100. Bu, elemanın genişliğinin % 100'üdür, yüksekliği değildir! Bu, genişliğinden daha büyük bir yüksekliğe sahip bir öğeniz varsa, bunu gizlemeyeceği anlamına gelir. Ayrıca, gerçek animasyon hızı tanımlanan hızdan tamamen farklıdır.
Timo Türschmann

3
Timo'nun yorumu hakkında daha fazla bilgi edene kadar VIDesignz'ın cevabı için heyecanlandım. Evet, margin-top(ve margin-bottom) yüzdelerde tanımlandığında genişliğe göredir, evet bu aptalca, ama aynı zamanda açık ve kapalı animasyon zamanlamalarının neden tamamen farklı olduğunu açıklıyor - en yüksek puanlı yanıtta gördüğünüzle aynı, kodlu maksimum yükseklik. Bunu yapmak neden bu kadar zor?
Kodlayıcı

52

CSS3 geçişlerini kullanarak yüksekliği canlandırmak için görsel bir çözüm, dolguya animasyon uygulamaktır.

Tam silme efekti elde edemezsiniz, ancak geçiş süresi ve dolgu değerleriyle oynamak sizi yeterince yaklaştırmalıdır. Yüksekliği / maks. Yüksekliği açıkça ayarlamak istemiyorsanız, aradığınız şey bu olmalıdır.

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'ın jsFiddle'ın üstünde)


3
Bence bu en iyi cevap. Bu teknik, çocuklardaki dolguların ayarlanmasına da uzanabilir. Benim durumumda, ortaya çıkan bazı içeriklerde açık yükseklik geçişleri ile birleştirebildim ve toplam etki, ortaya çıkması için iyi olan ancak garip bir anı getiren maksimum yükseklik çalışmasından çok daha başarılı. gizlemede gecikme. Er ya da geç benim app yanıt vermiyor yapar anlamsız bir gecikme tanıtmak hiç canlandırmaz. Birçok insanın bunun kabul edilebilir olduğunu düşünmesine şaşırdım.
Noktalı virgül

17
Bunun dışında burada yüksekliği hiç canlandırmıyorsunuz. Dolguyu canlandırıyorsunuz ... şu anki durumdan 0'a kadar canlandırabileceğinden iyi kaybolabilir, ancak genişlediğinde yakından izlerseniz metinle açılır ve daha sonra dolgu sadece canlandırır .. çünkü 0'dan otomatiğe nasıl animasyon yapılacağını bilmiyorum .... sayısal bir aralığa ihtiyacı var ... arası doldurma bu şekilde çalışır.
Rob R

Bu iyi bir çözüm değil hacky değil. Bu en iyi cevap değil bu soruya ama benim için çalıştı bir alternatiftir. Bazen sadece tam animasyon değil bazı yükseklik animasyon etkisi gerekir :)
Ivan Durst

Bu çözüm, bir geçiş gecikmesi kullanıldığında da başarısız olur.
Michel Joanisse

Ayrıca, bu çözümün, animasyonunuz yeterince hızlıysa oldukça akışkan geçişler sağlayan temiz bir çözüm olduğunu kabul ediyorum (benim durumumda 0,1 saniyelik geçişlere sahip bir akordeon için mükemmel!). Ama birçok uygulama paketi alışkanlık, ama ne de bu soruya anwsers!
Remi D

46

Geçici çözümüm, güzel ve pürüzsüz bir animasyon için maksimum yüksekliği tam içerik yüksekliğine geçirmektir, daha sonra içeriğin serbestçe yeniden boyutlandırılabilmesi için maksimum yüksekliği 9999 piksele ayarlamak için bir transitionEnd geri çağrısı kullanın.

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>


14
@ Derija93 Sade eski javascript zaman aşımı animasyonları kullanıyor. Zorluk bunun yerine CSS3 geçişlerini kullanmaktır.
Adam

3
İyi evet. Peki, örneğin, zaten zaten çok fazla "daha az yaz, daha fazlasını yap" kodu sağlayan bir kitaplık olan jQuery kullanıyorsanız "bunun yerine" CSS3 geçişlerini "neden kullanasınız ki? Hemen hemen herhangi bir web sitesinde çalıştırmak için jQuery kullanarak DEĞİLDİR, daha karmaşık olsa da, sürümün çok daha iyi görünebilir işaret etmek istedim. Sanırım çok yanlış ifade ettim. Üzgünüm. ;)
Kiruse

27
@ Derija93 Belki de CSS3 geçişleri (bulabildiğim tüm kaynaklara göre) jQuery animasyonlarından çok daha iyi bir performansa sahip olduğundan. (Aslında beni buraya getiren mevcut kullanım durumum için çok önemli.)
Mark Amery

4
@ Derija93 'Neden Javascript animasyonları CSS3 geçişleri bro ile karşılaştırıldığında yavaş çalışıyor ve jQuery animasyonları ile animasyon döngüsü hakkında endişelenmeniz gerekiyor. Tıklamada bir şeyi canlandırın, ardından hızla tıklayın ve animasyonların kendilerini tekrarladığını izleyin. Bu CSS3 ile ele alınır.
AlbertEngelB

2
@ Dropped.on.Caprica Bu biraz eski. Göstermeye çalıştığı konsepti yanlış anladığımı söylemiştim. Her neyse, basit animasyonlar .stopiçin, oldukça karmaşık animasyon döngüsü problemi için hile yapar. Şimdi yüksekliği ve rengi canlandırdığınızda ancak yalnızca yükseklik animasyonunu kesmek istediğinizde, işler biraz daha hileli hale geliyor ... Anladım.
Kiruse

43

Kabul edilen cevap çoğu durumda çalışır, ancak divyüksekliğiniz büyük ölçüde değişebiliyorsa iyi çalışmaz - animasyon hızı içeriğin gerçek yüksekliğine bağlı değildir ve dalgalı görünebilir.

Yine de gerçek animasyonu CSS ile gerçekleştirebilirsiniz, ancak kullanmaya çalışmak yerine öğelerin yüksekliğini hesaplamak için JavaScript kullanmanız gerekir auto. Uyumluluk istiyorsanız bunu biraz değiştirmeniz gerekebilir, ancak jQuery gerekli değildir (Chrome'un en son sürümünde çalışır :)).

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>


Bu yardımcı olabilir, ancak daha iyi bir örnek olmadan nasıl kullanılacağını bilmediğim için söyleyemem.
Ivan Durst

1
Sadece herhangi bir DOM öğesini (örneğin, document.getElementById('mydiv')veya ' dan $('#mydiv').get()) iletirsiniz ve işlev onu gizleme / gösterme arasında geçiş yapar. CSS geçişleri ayarlarsanız, öğe otomatik olarak animasyonlanır.
Oleg Vaskevich

Bir pasaj ekledim. Bunun dinamik boyutlu içerik için iyi çalışma avantajı vardır.
Oleg Vaskevich

3
-1, çünkü bu "CSS kullanmıyor". Sorunun amacı JS içermeyen bir çözümdür. Bence "doğru" cevap, bu bir hack değil, bu olurdu, ama ...
dudewad

16
JS kullanmak için downvote - cidden? Buradaki cevapların yarısında JS kullanılıyor, bu nedenle downvote'unuz adil veya gerekli görünmüyor. Ayrıca, bu cevap, IMO'nun OP'nin noktası olduğu gerçek animasyonu gerçekleştirmek için hala CSS kullanıyor. JS için kullanılan tek şey gerçek yüksekliği hesaplamaktır, çünkü saf CSS ile bunu yapmak imkansızdır (ve min-heightbeklenen cevapta olduğu gibi ayarlamak , listenin boyutu büyük ölçüde değişebildiğinde animasyon hızı ile ilgili sorunlara neden olur).
Oleg Vaskevich

30

Burada Element.scrollHeightyararlı olabilecek ve saf bir CSS geçişiyle kullanılabilecek özellikten çok az söz edildi . Özellik, içeriğinin daraltılmış yüksekliğin bir sonucu olarak taşmadığından ve nasıl taştığından (ör. height: 0) Bağımsız olarak her zaman bir öğenin "tam" yüksekliğini içerir .

Bu haliyle, height: 0(etkili bir şekilde tam olarak daraltılmış) bir eleman için, "normal" ya da "tam" yüksekliği, scrollHeightdeğeri (her zaman bir piksel uzunluğu) ile hala kolaylıkla temin edilebilir .

Bu tür bir eleman için, zaten varsayarak (kullanan, örneğin, gibi ayarlanır geçiş sahip ulözgün soru için):

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

Aşağıdaki gibi bir şeyle, yalnızca CSS kullanarak yüksekliğin istenen animasyonlu "genişlemesini" tetikleyebiliriz (burada uldeğişkenin listeyi ifade ettiği varsayılarak ):

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

Bu kadar. Listeyi daraltmanız gerekirse, aşağıdaki iki ifadeden biri yapılır:

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

Özel kullanım durumum, bilinmeyen ve genellikle önemli uzunluktaki animasyon listelerinin etrafında dönüyordu, bu yüzden keyfi bir "yeterince büyük" heightveya max-heightspesifikasyona ve aniden kaydırmanız gereken cut-off içeriğine veya riske ( overflow: autoörneğin) . Buna ek olarak, hareket hızı ve zamanlama ile kırılır max-heightkullanılan yüksekliği çok daha erken bunun için alacağını daha maksimum değere ulaşabilir, çünkü merkezli çözeltiler max-heightulaşamayacağı için 9999px. Ekran çözünürlükleri büyüdükçe, piksel uzunlukları 9999pxağzımda kötü bir tat bırakıyor. Bu özel çözüm bence problemi zarif bir şekilde çözüyor.

Son olarak, CSS adres yazarlarının gelecekteki revizyonlarının bu tür şeyleri daha da zarif bir şekilde yapması gerektiğini umuyoruz - "hesaplanmış" ve "kullanılmış" ve "çözülmüş" değerler kavramını tekrar gözden geçirin ve geçişlerin hesaplananlar için geçerli olup olmayacağını düşünün widthve height(şu anda biraz özel bir muamele gören) geçişleri de dahil olmak üzere değerler .


6
Bu özelliği diğer yanıtlarda bulamadınız çünkü Element.scrollHeightözelliği kullanarak DOM ile etkileşim kurmak JavaScript gerektirir ve sorunun açıkça belirttiği gibi bunu JavaScript olmadan yapmak isterler .
TylerH

3
CSS'nin, bu sorunu çözebilecek iki sahte sınıf dışında, sayfa 1'deki en yüksek oylanan cevapların gösterdiği gibi, birçok başka kısmı vardır. JavaScript'te bir stil ayarlamak "saf CSS" değildir, çünkü JS'nin ilk etapta ayarlanmasını gerektirir. Genellikle bir kişi yalnızca CSS çözümü istediğinde, bunun nedeni herhangi bir JavaScript enjekte edememesi veya mevcut projesi veya rolü tarafından izin verilmemesidir.
TylerH

29

max-heightHer durum için farklı geçiş kolaylaştırması ve gecikmesi ile kullanın .

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

Örneğe bakın: http://jsfiddle.net/0hnjehjc/1/


12
Buradaki sorun, dinamik bir ortamda yeterli alanınızın olmasını sağlamak için, gibi saçma maksimum yükseklikleri kullanmanız gerekir 999999px. Bu, kareler bu değerden hesaplandığından, animasyonunuzu kaydırır. Böylece bir yönde animasyon "gecikmesi" ve diğer yönde gerçekten hızlı bir sonla sonuçlanabilir (düzeltme: zamanlama fonksiyonları)
Julian F. Weinert

29

Sabit kodlanmış değer yok.

JavaScript yok.

Yaklaşım yok.

İşin püf noktası div, tarayıcının% 100'ün ne anlama geldiğini anlamasını sağlamak için gizli ve çoğaltılmış kullanmaktır .

Bu yöntem, canlandırmak istediğiniz öğenin DOM'sini çoğaltabildiğinizde uygundur.

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


Güzel yapılır - bu gerçekten olmaması gereken bir probleme geçerli bir çözümdür. Geçiş "doğrusal" olarak ayarlanmadığı sürece maksimum yüksekliği animasyon bastır, ayrıca yüksekliğin değişken olduğu CMS içeriğini canlandırmak için de çok açıktır.
M_Willett

Bu akıllıca, ancak bunun için DOM öğelerini ve içeriğini çoğaltmaktan rahat olmazdım.
Andre Figueiredo

Bunu bir kapsayıcı olmadan yapabilir ve animasyonla daha fazla performans yapabilirsiniz transform: scaleY(1), çünkü bu geçiş alanı kaldırmaz.
Fabian von Ellerts

21

Bunu gönderdiğimde 30'dan fazla cevap var, ama cevabımın jake tarafından zaten kabul edilen cevapta iyileştiğini hissediyorum .

Basitçe kullanmaktan max-heightve CSS3 geçişlerinden kaynaklanan sorundan memnun değildim , çünkü birçok yorumcunun belirttiği gibi, max-heightdeğerinizi gerçek yüksekliğe çok yakın olarak ayarlamanız gerekiyor veya bir gecikme alacaksınız. Bu sorunun bir örneği için bu JSFiddle'a bakın .

Bu sorunu aşmak için (hala JavaScript kullanmıyorken), transform: translateYCSS değerini değiştiren başka bir HTML öğesi ekledim .

Hem bu araçlar max-heightve translateYkullanılır: max-heightiken, bunun altındaki elemanlar aşağı itmek için eleman verir translateYistediğimiz "anlık" bir etki verir. İle ilgili sorun max-heighthala var, ancak etkisi azalıyor. Bu, max-heightdeğeriniz için çok daha yüksek bir yükseklik ayarlayabileceğiniz ve daha az endişelenebileceğiniz anlamına gelir .

Genel faydası, geri dönüşte (daraltma), kullanıcının translateYanimasyonu hemen görmesidir , bu yüzden ne kadar süreceği önemli değildir max-height.

Keman Olarak Çözüm

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>


Güzel karşılaştırma @davidtaubmann, kaleminiz farklılıkları çok iyi gösteriyor! Birlikte gitti translateYüzerinde scalenasıl sevmedim çünkü scaleo sıkıştırma etkisi verdi.
Andrew Messier

Teşekkürler @ andrew-messier, yorumu sildim çünkü bir hata var, translateY codepen.io/davidtaubmann/pen/zKZvGP'de dışlanmıyor (çünkü hareketi yapacak çocuk yok, düzeltmeye ihtiyaç duyuyor) ... ama bu bir SADECE MAX-HEIGHT karşılaştırmasını mükemmel bir şekilde görebilir ve ölçekle karıştırabiliriz (diğer cevaplarda belirtildiği gibi): codepen.io/davidtaubmann/pen/jrdPER . Tüm bunlar kullandığım bir Hedef metodolojisinde bana çok yardımcı oldu
DavidTaubmann

18

Tamam, sanırım süper basit bir cevap buldum ... hayır max-height, relativekonumlandırma kullanıyor , lielemanlar üzerinde çalışıyor ve saf CSS. Firefox'tan başka bir şey test etmedim, CSS'ye bakılırsa da, tüm tarayıcılarda çalışması gerekiyor.

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>

13
Bu, elemanın yüksekliği genişliğini aşana kadar çalışacaktır. Kenar boşluklarının yüzdeler kullanılarak nasıl hesaplandığının temelidir: bunlar öğenin genişliğine göre hesaplanır. 1000 piksel genişliğinde bir öğeniz varsa, bu çözümün çalışması için 1100 piksel büyüklüğünde bir öğe çok büyük olacaktır, yani bu negatif üst kenar boşluğunu artırmanız gerekir. Temel olarak, yükseklik veya maksimum yükseklik kullanmakla aynı problem.
dudewad

15

DÜZENLEME: Güncellenmiş cevap için aşağı kaydırın
Bir açılır liste yapıyordum ve bu gönderiyi gördüm ... birçok farklı cevap var ama açılır listemi de paylaşmaya karar verdim, ... Mükemmel değil ama en azından sadece css kullanacak yıkılmak! Listeyi görünüme dönüştürmek için transform: translateY (y) kullanıyorum ...
Testte daha fazlasını görebilirsiniz
http://jsfiddle.net/BVEpc/4/
Her li'nin arkasına div yerleştirdim çünkü benim aşağı açılan liste yukarı geliyor ve düzgün göstermek için bu gerekli, benim div kodu:

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

ve fareyle üzerine gelme:

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

ve ul yüksekliği içeriğe ayarlandığından, vücut içeriğinizin üstesinden gelebilir, bu yüzden bunu ul için yaptım:

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

ve üzerine gelin:

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

Geçişten sonra ikinci kez gecikme olur ve açılır listem hareketli bir şekilde kapatıldıktan
sonra gizlenir ... Umarım daha sonra birisi bundan yararlanır.

EDIT: ppl aslında bu prototip kullanarak inanamıyorum! Bu açılır menü sadece bir alt menü içindir ve hepsi bu! IE 8 desteği ile hem ltr hem de rtl yönü için iki alt menü olabilir daha iyi bir güncelledik.
LTR için
keman RTL için keman
Umarım birileri bunu gelecekte faydalı bulur.


11

Min. Yükseklik ve maksimum yükseklik de sağlayarak yükseklik: 0'dan yükseklik: otomatik olarak geçiş yapabilirsiniz.

div.stretchy{
    transition: 1s linear;
}

div.stretchy.hidden{
    height: 0;
}

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

@Stuart Badminton çalışma örneği verebilir misiniz? Bunu bir araya getirdim ama hiçbir yerde çalışmıyor gibi görünüyor :( jsfiddle.net/gryzzly/n5XfG
Misha Reyzlin

5
Sorun geçiş kuralınızla ilgili. çalışabilmesi için minimum ve maksimum yüksekliğe geçişi de uygulamanız gerekir. geçiş: yükseklik .5s doğrusal, min-yükseklik .5s doğrusal, max-yükseklik .5s doğrusal
Stuart Badminton

2
daha sonra söylediğin gibi, maksimum yüksekliği canlandırmak için ihtiyacım olan şey: jsfiddle.net/gryzzly/n5XfG/3
Misha Reyzlin

11
Tabii ki, bununla ilgili bir sorun var. Maksimum yüksekliği canlandırmak için gereken süre, kutunun otomatik yüksekliğine geçiş için geçen süre değildir: maksimum yüksekliğin animasyonu bitmeden önce otomatik olarak yüksekliğe ulaşır. Benzer şekilde, 0'a geçerken, maksimum yükseklik yükseklikten daha büyük bir yükseklikte başladığı için geçiş hemen başlamaz: otomatik. Maksimum yüksekliğe geçiş: 1000 piksel
stephband

Haklısın, ileri testlerde bunu fark ettim. Tam bir yükseklik: 0 - yükseklik: otomatik hiç uygulanacak mı bilmiyorum ama bazı durumlarda maksimum yükseklik kullanmak, yalnızca CSS kullanarak aksi takdirde imkansız bir durumu çözüyor.
Stuart Badminton

10

Flexbox Çözümü

Artıları:

  • basit
  • JS yok
  • yumuşak bir geçiş

Eksileri:

  • elemanın sabit yükseklikte esnek bir kaba konması gerekir

Çalışma şekli her zaman esnek temele sahip olmaktır: içerikli öğeye otomatik geçiş ve bunun yerine flex-grow ve flex-shrink geçişleri.

Düzenleme: Xbox One arayüzünden esinlenerek geliştirilmiş JS Fiddle.

* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
  transition: 0.25s;
  font-family: monospace;
}

body {
  margin: 10px 0 0 10px;
}

.box {
  width: 150px;
  height: 150px;
  margin: 0 2px 10px 0;
  background: #2d333b;
  border: solid 10px #20262e;
  overflow: hidden;
  display: inline-flex;
  flex-direction: column;
}

.space {
  flex-basis: 100%;
  flex-grow: 1;
  flex-shrink: 0;    
}

p {
  flex-basis: auto;
  flex-grow: 0;
  flex-shrink: 1;
  background: #20262e;
  padding: 10px;
  width: 100%;
  text-align: left;
  color: white;
}

.box:hover .space {
  flex-grow: 0;
  flex-shrink: 1;
}
  
.box:hover p {
  flex-grow: 1;
  flex-shrink: 0;    
}
<div class="box">
  <div class="space"></div>
  <p>
    Super Metroid Prime Fusion
  </p>
</div>
<div class="box">
  <div class="space"></div>
  <p>
    Resident Evil 2 Remake
  </p>
</div>
<div class="box">
  <div class="space"></div>
  <p>
    Yolo The Game
  </p>
</div>
<div class="box">
  <div class="space"></div>
  <p>
    Final Fantasy 7 Remake + All Additional DLC + Golden Tophat
  </p>
</div>
<div class="box">
  <div class="space"></div>
  <p>
    DerpVille
  </p>
</div>

JS Fiddle


7

@ Jake'nin cevabını genişleterek, geçiş maksimum yükseklik değerine kadar gidecek ve son derece hızlı bir animasyona neden olacak - her ikisi için geçişleri ayarlarsanız: vurgulu ve kapalı, çılgın hızı biraz daha kontrol edebilirsiniz.

Bu yüzden li: hover, fare duruma girdiğinde ve daha sonra üzerine gelinmeyen özellikteki geçiş fare izni olacaktır.

Umarım bu biraz yardımcı olacaktır.

Örneğin:

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

İşte bir keman: http://jsfiddle.net/BukwJ/


1
Bunun neden -1 olduğunu bilmiyorum. Aslında bu javascript bir sürü ekleyerek bazı insanlardan daha iyi bir girişim olduğunu düşünüyorum. Mükemmel bir çözüm değil, ama bazı ince ayarlarla iyi bir iş çıkarıyor, bunu dönüş değeri için çalışmak için buldum. geçiş: 500ms kübik bezier (0.000, 1.225, 0.085, 0.385); Bu, açılışta 2s geçişine, ardından başlangıç ​​durumuna geri dönmek için yukarıdaki koda dayanıyordu. Teşekkürler ... Bu, yukarıdakilerin hepsinden daha iyi oldu. +1 Bu siteyi bezier oluşturmak için kullandım matthewlein.com/ceaser
gcoulby

Tamam biraz daha tweaking aldı. geçiş: 500ms kübik bezier (0.000, 1.390, 0.000, 0.635); Geçişimin% 5 -% 100 arasında olduğunu belirtmeliyim (ancak gerçekte son değer yaklaşık% 28'dir) bu yüzden projeye bağlıdır.
gcoulby

Kesinlikle, ideal değil, ama ortalama yüksekliğin ne olacağı hakkında yuvarlak biliyorsanız hızlı bir düzeltme.
jamie

7

Bence gerçekten sağlam bir çözüm buldum

TAMAM! Bu sorunun internet kadar eski olduğunu biliyorum ama sanırım mutant-geçiş adı verilen bir eklentiye dönüştürdüğüm bir çözümüm var . style=""Çözümüm, DOM'da her değişiklik olduğunda izlenen öğelerin özniteliklerini ayarlar . sonuç, geçişleriniz için iyi ole CSS kullanabileceğiniz ve hacky düzeltmeleri veya özel javascript kullanamayacağınızdır. Yapmanız gereken tek şey, söz konusu öğeyi kullanarak izlemek istediğiniz öğeyi ayarlamaktır data-mutant-attributes="X".

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

Bu kadar! Bu çözüm, DOM'daki değişiklikleri izlemek için MutationObserver kullanır . Bu nedenle, hiçbir şeyi manuel olarak canlandırmak için hiçbir şey ayarlamanız veya javascript kullanmanız gerekmez. Değişiklikler otomatik olarak izlenir. Ancak, MutationObserver kullandığından, bu yalnızca IE11 + 'da geçiş yapar.

Kemanlar!


12
Genellikle, birisi "JavaScript olmadan" bir şeyin nasıl yapılacağını sorduğunda, çözümün JavaScript'in devre dışı bırakıldığı tarayıcılarda çalışması gerektiği anlamına gelir. "Kendi senaryolarımı yazmadan" demek değildir. Eklentinizin JavaScript kullanmadan kullanılabileceğini söylemek en iyi yanıltıcıdır - bir JavaScript eklentisi olduğu düşünülürse.
BoltClock

Açıklığa kavuşturmalıyım, Özel bir javascript kullanmak zorunda olmadığınızı söylediğimde, herhangi bir javascript yazmak zorunda olmadığınız anlamına gelir . yalnızca JS kitaplığını ekleyin ve HTML'de hangi özellikleri izlemek istediğinizi belirtin. Sabit yükseklikli css kullanmak veya herhangi bir şey bulmak zorunda değilsiniz. sadece stil ve git.
JonTroncoso

"(...) hiçbir şeyi manuel olarak canlandırmak için hiçbir şey ayarlamanız veya javascript kullanmanız gerekmez (...)", bu nedenle eğlenmek için JavaScript kullanıyorsunuz
Roko C. Buljan

6

Düğüm başına sabit kod veya başlatmak için herhangi bir kullanıcı kodu gerektirmeden 0 dahil herhangi bir başlangıç ​​yüksekliğinden otomatik (tam boyut ve esnek) geçişe geçmenin bir yolu: https://github.com/csuwildcat / geçiş-otomatik . Bu temelde ne istediğiniz için kutsal kâse, inanıyorum -> http://codepen.io/csuwldcat/pen/kwsdF . Aşağıdaki JS dosyasını sayfanıza atmanız yeterlidir ve bundan sonra tek reveal=""yapmanız gereken, genişletmek ve daraltmak istediğiniz düğümlerden tek bir boolean özniteliği eklemek / kaldırmaktır .

Örnek kodun altında bulunan kod bloğunu ekledikten sonra kullanıcı olarak tek yapmanız gereken:

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

Sayfanıza eklenecek kod bloğu, bundan sonra hepsi et sosu:

Bu JS dosyasını sayfanıza bırakın - hepsi Just Works ™

/ * Yükseklik kodu: otomatik; geçiş * /

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

/ * DEMO kodu * /

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

9
Bu, önerilenden daha temiz ve esnek bir çözüm olsa da, şahsen bunun JS'nin dokunması gereken bir şey olmaması gerektiğine inanıyorum. Yanlış olduğunu söylememek, sadece iç çekiş.
mystrdat

@mystrdat açık olsa da, JS yalnızca belirli koşulları izlemek ve izlediği olaylara / koşullara bağlı olarak birkaç özellik / geçici CSS değeri eklemek için kullanılır. Geçiş hala CSS'de yapılıyor. Katılıyorum, görünüşte basit bir kullanım durumunu gerçekten tatmin etmek için bu kurulum seviyesinin ve el tutmanın gerekli olması üzücü! : /
csuwldcat

1
@KarolisRamanauskas hayır bu bir sorun değil - IE hem CSS Anahtar Karelerini hem de requestAnimationFrame'i destekler. clipBenim kukla özellik tetikleyici olarak kullanıyordum ve bir nedenden dolayı IE klibin canlandırılmasına izin verdi. Opaklığa geçtim ve hepsi tekrar çalışıyor: codepen.io/csuwldcat/pen/FpzGa . Cevabın eşleşmesi için kodu güncelledim.
csuwldcat

1
@csuwldcat Çok güzel bir çözüm, içeriğin küçük bir kısım için göründüğünü ve kaybolduğunu fark ettim, bu neden oluyor? Önlenebilir mi?
Beto Aveiga

12
Bunu değerlendirmek istiyorum, ancak nasıl çalışacağını sormak yerine, çalışmasını sağlamak için yazdığınız bir eklentiyi paylaştınız. Meraklı olarak, eklentinizi tersine çevirmek için bırakıyoruz, bu çok eğlenceli değil. Eklentinizin ne yaptığına ve nedenine ilişkin daha fazla açıklama içerecek şekilde yanıtınızı güncellemenizi dilerim. Kodu daha açıklayıcı olacak şekilde değiştirin. Örneğin, yalnızca statik CSS yazan bir kod bölümü var. Onu üreten kod yerine, CSS görmek istiyorum. Tüm tarayıcı önekleri için tekrarlama gibi sıkıcı parçaları dışarıda bırakabilirsiniz.
gilly3

6

Jake'in maksimum yüksekliği canlandırmak için cevabı harika, ama büyük bir maksimum yükseklik rahatsız edici ayarlamanın neden olduğu gecikmeyi buldum.

Daraltılabilir içeriği bir iç bölüme taşıyabilir ve iç bölümün yüksekliğini elde ederek maksimum yüksekliği hesaplayabiliriz (JQuery aracılığıyla, dış yükseklik () olurdu).

$('button').bind('click', function(e) { 
  e.preventDefault();
  w = $('#outer');
  if (w.hasClass('collapsed')) {
    w.css({ "max-height": $('#inner').outerHeight() + 'px' });
  } else {
    w.css({ "max-height": "0px" });
  }
  w.toggleClass('collapsed');
});

İşte bir jsfiddle bağlantısı: http://jsfiddle.net/pbatey/duZpT

İşte gerekli minimum kodu içeren bir jsfiddle: http://jsfiddle.net/8ncjjxh8/


5

Bu iş parçacığının yaşlandığını anlıyorum, ancak belirli Google aramalarında yüksek sırada yer alıyor, bu yüzden güncellenmeye değer olduğunu düşünüyorum.

Ayrıca öğenin kendi yüksekliğini de alırsınız / ayarlarsınız:

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

Bu Javascript'i, hedef_kutusunun satır içi komut dosyası etiketindeki kapanış etiketinden hemen sonra dökmeniz gerekir.


document.getElementById ('target_box'). getBoundingClientRect (). yükseklik en iyisini yapmalıdır.
değiştirmek

5

Bunu yapabildim. Bir var .child& bir .parentdiv. Çocuk div, absolutekonumlandırma ile ebeveynin genişliğine / yüksekliğine mükemmel uyum sağlar . Sonra değeri aşağı translateitmek özelliği animasyon . Çok pürüzsüz animasyonu, aksaklık veya aşağı taraf yok.Y100%

Böyle bir şey, sözde kod

.parent{ position:relative; overflow:hidden; } 
/** shown state */
.child {
  position:absolute;top:0;:left:0;right:0;bottom:0;
  height: 100%;
  transition: transform @overlay-animation-duration ease-in-out;
  .translate(0, 0);
}

/** Animate to hidden by sliding down: */
.child.slidedown {
  .translate(0, 100%); /** Translate the element "out" the bottom of it's .scene container "mask" so its hidden */
}

Bir belirtmek istiyorum heightüzerine .parentde, px, %gibi veya izinli auto. Bu div daha sonra .childaşağı kaydırıldığında div'ı maskeler .


Bunun çalışma örneği çok takdir edilecektir.
Nörotransmitter

5

Bazı JavaScript ile bir cevap yayınladım ve aşağı indirildim, bu yüzden rahatsız ve tekrar denedim ve sadece CSS ile kırık var!

Bu çözüm birkaç 'teknik' kullanır:

  • padding-bottom:100%yüzdelerin öğenin geçerli genişliği açısından tanımlandığı 'hack'. Bu teknik hakkında daha fazla bilgi.
  • şamandıra büzülme sargısı, (şamandıra temizleme hackini uygulamak için ekstra bir div gerektirir)
  • https://caniuse.com/#feat=css-writing-mode ve onu geri almak için bazı dönüşümlerin olağandışı kullanımı (bu, yukarıdaki dolgu kesmekinin dikey bir bağlamda kullanılmasına izin verir)

Sonuç olarak, yalnızca CSS kullanarak performans geçişi ve geçişi sorunsuz bir şekilde gerçekleştirmek için tek bir geçiş fonksiyonu elde etmemiz; kutsal kâse!

Tabii ki, bir dezavantajı var! İçeriğin kesildiği ( overflow:hidden) genişliğini nasıl kontrol edeceğimi bilemiyorum ; dolgu alt kesmek nedeniyle, genişlik ve yükseklik yakından ilişkilidir. Yine de bir yol olabilir, bu yüzden ona geri dönecektir.

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>


Bunun diğer dezavantajı, imleci onlarla etkileşim kurmak için imleci "hoverme" div öğesinden öğe listesine taşıyamazsınız (görünüşte OP sorma nedeni), bu yüzden sadece bir araç ipucu işlevi olarak yararlı değil , diyelim ki iç içe alt menülere sahip bir menü.
TylerH

Bu sadece sorunun formüle edilmesinin bir sonucudur ve teknikle ilgili değildir. İsterseniz tetiği bir input[type="checkbox"]:checkedyerine değiştirebilirsiniz :hover(yani, herhangi bir sınıf eklemek için JavaScript kullanmak istemezsiniz)
EoghanM

Yani, sorunun nasıl formüle edildiğine bakılmaksızın, bir çözümün uygulanması bu kadar sınırlıysa, muhtemelen bu çözümün cevabında (veya tercihen hesaba katılır ) belirtilmelidir. Bu çözümün 'kutsal bir kâse' olduğunu söylüyorsunuz, ancak geçişli div'in üzerine gelinemiyor bile ... benim için böyle bir nihai çözüm gibi görünmüyor.
TylerH

Merhaba @TylerH, özür dilerim, orijinal sorudaki tetikleyicinin genişletilmiş listeyi çevrelediği gerçeğini kaçırdım, bu yüzden liste üzerine geldiğinde açık kalmalıdır. Cevabımı bunu yansıtacak şekilde güncelledim. Daha önce de belirttiğim gibi, sadece CSS'de mümkün olmadığı düşünülen yeni bir teknik sunuyorum (birkaç yıldır bir çözüm arıyordum).
EoghanM

4

İşte jQuery ile birlikte kullandığım bir çözüm. Bu, aşağıdaki HTML yapısı için çalışır:

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

ve fonksiyon:

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

Ardından, yüksekliği ayarlamak ve kaldırmak için bir tıklama işlevi kullanabilirsiniz. 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 }

bu en yeni jquery sürümü ile düzgün görünmüyor
oliverbachmann

4

Son zamanlarda sarma yerine öğeleri max-heightüzerinde geçiş .liul

Muhakeme Küçük için gecikme olmasıdır max-heightsbüyük kıyasla (hiç değilse) çok daha az fark olduğunu max-heights, ve de benim ayarlayabilirsiniz max-heightgöre ilgili değer font-sizearasında likullanarak ziyade bazı keyfi büyük sayısından daha emsya rems.

Yazı tipi boyutum ise 1rem, (sarılmış metni yerleştirmek için) max-heightgibi bir şeye ayarlayacağım 3rem. Burada bir örnek görebilirsiniz:

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


3

Her şeyi ayrıntılı olarak okumadım ama son zamanlarda bu problemi yaşadım ve aşağıdakileri yaptım:

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

Bu, ilk önce 200 piksel yüksekliğe kadar içeriği gösteren bir div'e sahip olmanızı sağlar ve fareyle üzerine gelindiğinde boyutu en azından div'ın tüm içeriği kadar yüksek olur. Div 3000px değil, 3000px benim empoze ettiğim sınır. Geçiş olmayan: üzerinde geçiş yaptığınızdan emin olun, aksi takdirde garip bir görüntü elde edebilirsiniz. Bu şekilde: vurgulu vurgulu olmayandan miras alır.

% Px veya otomatik olarak form px'den geçiş çalışmaz. Aynı ölçü birimini kullanmanız gerekir. Bu benim için iyi çalışıyor. HTML5 kullanmak mükemmel yapar ....

Her zaman etrafında bir çalışma olduğunu unutmayın ...; )

Umarım birisi bunu faydalı bulur


3

Sağlanan sabit kodlu maksimum yükseklik değeri gerçek yükseklikten çok daha büyük değilse, Jake'in maksimum yükseklik çözümü iyi çalışır (çünkü aksi takdirde istenmeyen gecikmeler ve zamanlama sorunları vardır). Diğer taraftan, sabit kodlanmış değer yanlışlıkla gerçek yükseklikten büyük değilse, eleman tamamen açılmaz.

Aşağıdaki yalnızca CSS çözümü, gerçek boyutların çoğundan daha büyük olması gereken sabit kodlu bir boyut gerektirir. Bununla birlikte, gerçek boyut bazı durumlarda sabit kodlu boyuttan büyükse bu çözüm de işe yarar. Bu durumda geçiş biraz atlayabilir, ancak asla kısmen görünür bir eleman bırakmaz. Dolayısıyla bu çözüm, örneğin içeriğin genellikle x pikselden daha büyük olmadığını bildiğiniz bir veritabanından bilinmeyen içerik için de kullanılabilir, ancak istisnalar vardır.

Fikir, kenar boşluğu (veya biraz farklı bir animasyon için kenar boşluğu) için negatif bir değer kullanmak ve içerik öğesini taşma: gizli bir orta öğeye yerleştirmektir. İçerik elemanının negatif kenar boşluğu böylece orta elemanın yüksekliğini azaltır.

Aşağıdaki kod, kenar boşluğunda -150px'den 0px'e geçiş kullanır. İçerik öğesi 150 pikselden yüksek olmadığı sürece bu tek başına iyi çalışır. Ayrıca orta eleman için maksimum yükseklikte 0 piksel ile% 100 arasında bir geçiş kullanır. İçerik öğesi 150 pikselden yüksekse, bu son olarak orta öğeyi gizler. Maksimum yükseklik için geçiş, pürüzsüz bir görsel efekt için değil, uygulamayı kapatırken bir saniye geciktirmek için kullanılır (ve bu nedenle 0 piksel ile% 100 arasında çalışabilir).

CSS:

.content {
  transition: margin-bottom 1s ease-in;
  margin-bottom: -150px;
}
.outer:hover .middle .content {
  transition: margin-bottom 1s ease-out;
  margin-bottom: 0px
}
.middle {
  overflow: hidden;
  transition: max-height .1s ease 1s;
  max-height: 0px
}
.outer:hover .middle {
  transition: max-height .1s ease 0s;
  max-height: 100%
}

HTML:

<div class="outer">
  <div class="middle">
    <div class="content">
      Sample Text
      <br> Sample Text
      <br> Sample Text
      <div style="height:150px">Sample Test of height 150px</div>
      Sample Text
    </div>
  </div>
  Hover Here
</div>

Kenar boşluğu tabanı değeri negatif olmalı ve içerik öğesinin gerçek yüksekliğine mümkün olduğunca yakın olmalıdır. Eğer (mutlak değer) daha büyükse, maksimum kodlu çözümlerde olduğu gibi benzer gecikme ve zamanlama problemleri vardır, ancak sabit kodlanmış boyut gerçek olandan çok daha büyük olmadığı sürece sınırlandırılabilir. Kenar boşluğu için mutlak değer gerçek yükseklikten küçükse, tansition biraz atlar. Her durumda geçişten sonra içerik öğesi tamamen görüntülenir veya tamamen kaldırılır.

Daha fazla bilgi için blog yazım http://www.taccgl.org/blog/css_transition_display.html#combined_height


3

Bunu, klip yollu bir ters (daralt) animasyon oluşturarak yapabilirsiniz.

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


2

Bu tam olarak soruna bir "çözüm" değil, daha çok bir çözüm. Sadece metinle yazılmış şekilde çalışır, ancak gerektiğinde diğer öğelerle çalışmak için değiştirilebilir.

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

İşte bir örnek: http://codepen.io/overthemike/pen/wzjRKa

Temel olarak, yazı tipi boyutunu 0 olarak ayarlayıp yüksekliği, maksimum yükseklik veya scaleY () vb. Gerçek yüksekliği CSS ile otomatik olarak dönüştürmek şu anda mümkün değildir, ancak içindeki içeriği dönüştürmek, dolayısıyla yazı tipi boyutu geçişidir.

  • Not - kod alanında IS javascript var, ancak tek amacı akordeon için tıklandığında css sınıflarını eklemek / kaldırmaktır. Bu gizli radyo düğmeleriyle yapılabilir, ama ben buna odaklanmadım, sadece yükseklik dönüşümü.

1
Bu cevabı etkili bir şekilde çoğaltır , ancak opaklık-solma efektini atlar.
Nadiren

Kabul. Daha iyi bir yaklaşım.
Mike
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.