Bagaimana saya bisa transisi tinggi: 0; untuk ketinggian: otomatis; menggunakan CSS?

2136

Saya mencoba membuat <ul>slide menggunakan transisi CSS.

The <ul>dimulai di height: 0;. Saat mengarahkan, ketinggian diatur ke height:auto;. Namun, ini menyebabkannya hanya muncul, bukan transisi,

Jika saya melakukannya dari height: 40px;ke height: auto;, maka akan meluncur ke atas height: 0;, dan kemudian tiba-tiba melompat ke ketinggian yang benar.

Bagaimana lagi saya bisa melakukan ini tanpa menggunakan JavaScript?

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

Hailwood
sumber
Saya yakin height:auto/max-heightsolusinya hanya akan berfungsi jika Anda memperluas area yang lebih besar daripada yang heightingin Anda batasi. Jika Anda memiliki max-heightdari 300px, tapi combo box dropdown, yang dapat kembali 50px, maka max-heighttidak akan membantu Anda, 50pxadalah variabel tergantung pada jumlah elemen, Anda dapat tiba ke situasi sulit di mana aku tidak bisa memperbaikinya karena heighttidak diperbaiki, height:autoadalah solusinya, tetapi saya tidak dapat menggunakan transisi dengan ini.
Christopher Thomas
51
OP sedang mencoba untuk solusi css, bukan js, kalau tidak mereka hanya bisa menggunakan overflow dan menghidupkan
Toni Leigh
5
@VIDesignz: Tetapi div dalam -100% margin-top menerima lebar div pembungkus, bukan tinggi. Jadi solusi ini memiliki masalah yang sama, yaitu solusi max-height. Apalagi ketika lebarnya lebih kecil dari ketinggian konten, tidak semua konten disembunyikan oleh -100% margin-top. Jadi ini solusi yang salah.
GregTom
1
Lihat github.com/w3c/csswg-drafts/issues/626 untuk diskusi seputar spesifikasi dan implementasi solusi yang tepat
Ben Creasy

Jawaban:

2745

Gunakan max-heightdalam transisi dan tidak height. Dan tetapkan nilai pada max-heightsesuatu yang lebih besar dari yang pernah didapat kotak Anda.

Lihat demo JSFiddle yang disediakan oleh Chris Jordan dalam jawaban lain di sini.

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

jake
sumber
324
ini bekerja dengan baik! kecuali ada penundaan ketika mulai, karena itu dimulai untuk max-tinggi yang awalnya sangat tinggi .. hmm, saya pikir ini agak menjengkelkan
vsync
175
+1 Solusi hebat! Kecepatan transisi dihitung dihitung sebagai waktu yang Anda tentukan untuk transisi ke nilai max-height ... tetapi karena tinggi akan kurang dari max-tinggi, transisi ke tinggi aktual akan terjadi lebih cepat (sering secara signifikan) daripada waktu yang ditentukan.
kingjeffrey
50
Perhatikan bahwa ini dapat menyebabkan transisi yang buruk berakhir ketika Anda harus menggunakan nilai yang jauh lebih besar dari nilai yang sebenarnya dihitung. Saya perhatikan ini ketika mencoba membuat div tumbuh dari 0 tinggi ke tinggi konten yang sangat bervariasi karena ukuran layar yang berbeda (2 baris pada monitor 2560x1440 saya vs> 10 baris pada smartphone). Untuk ini saya akhirnya pergi dengan js.
jpeltoniemi
44
Solusi yang sangat jelek karena menciptakan penundaan pada satu arah tetapi tidak pada yang lain.
Tim
84
Ini adalah solusi yang cukup malas. Saya berasumsi OP ingin menggunakan ketinggian: otomatis karena ketinggian kontainer yang diperluas agak tidak dapat diprediksi. Solusi ini akan menyebabkan penundaan sebelum animasi terlihat. Selain itu durasi animasi yang terlihat tidak dapat diprediksi. Anda akan mendapatkan hasil yang jauh lebih mudah diprediksi (dan mungkin lebih mulus) dengan menghitung tinggi gabungan dari masing-masing simpul wadah anak dan kemudian mereda ke nilai ketinggian yang tepat.
Shawn Whinnery
314

Anda harus menggunakan scaleY sebagai gantinya.

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>

Saya telah membuat versi awalan vendor kode di atas pada jsfiddle , dan mengubah jsfiddle Anda untuk menggunakan scaleY alih-alih tinggi.

dotnetCarpenter
sumber
6
Saya mengangkat jawaban ini karena ini berfungsi dengan baik di browser yang mampu transisi css3, tetapi harus dicatat bahwa ini tidak akan bekerja sama sekali di IE <9 , dan tidak akan dianimasikan (hanya akan melompat) di IE <10
Hailwood
215
Metode ini hanya mencapai sebagian efek yang diinginkan tetapi tidak benar-benar menghilangkan ruang. Kotak yang ditransformasikan bertindak seperti elemen yang relatif diposisikan - ruang diambil tidak peduli bagaimana itu diskalakan. Lihat jsFiddle ini yang mengambil yang pertama dan hanya menambahkan beberapa teks palsu di bagian bawah. Perhatikan bagaimana teks di bawahnya tidak bergerak ke atas saat tinggi kotak diskalakan ke nol.
animuson
9
Sekarang berhasil: jsfiddle.net/gNDX3/1 Pada dasarnya Anda perlu mendesain elemen Anda sesuai dengan yang Anda butuhkan. Tidak ada peluru atau widget seperti perilaku di CSS / HTML.
dotnetCarpenter
70
Sementara saya memuji seseorang yang mencoba pendekatan yang berbeda, efek dan komplikasi dunia nyata yang dibawa solusi ini jauh lebih buruk daripada peretasan max-height yang mengerikan. Tolong jangan gunakan.
mystrdat
2
@ SquareCat baik-baik saja. Berikut ini adalah laci yang lebih seperti: jsfiddle.net/dotnetCarpenter/WTL2r
dotnetCarpenter
202

Saat ini Anda tidak dapat menghidupkan ketinggian ketika salah satu ketinggian yang terlibat adalah auto, Anda harus menetapkan dua ketinggian eksplisit.

robertc
sumber
12
Biasanya ada beberapa cara untuk memecahkan masalah, dan tidak semuanya sesuai atau mungkin. Saya tidak tahu mengapa @JedidiahHurt dan Ryan Ore mencoba membatasi kemungkinan jawaban di situs tanya jawab. Apalagi mengingat jawaban ini ada di sini dulu. Keraguan demikian karena jawaban yang diterima adalah solusi.
Hooray Im Helping
5
Jawaban dari @ jake tidak elegan dan tidak benar. Jawaban yang ditautkan di sini jauh lebih baik. Ini bekerja dengan benar dan menangani semua kasus ukuran - tidak ada yang bisa dikatakan dari jawaban yang diterima.
GraphicsMuncher
5
Yup: yathis.$element[dimension](this.$element[dimension]())[0].offsetHeight
Andy
4
Apakah ini direncanakan untuk diperbaiki? Maksud saya, ini sangat wajar untuk dapat beralih dari 0 tinggi ke auto...
Augustin Riedinger
6
@Meliodas "tidak / tidak bisa" adalah jawaban yang valid dan dapat diterima untuk pertanyaan di Stack Overflow.
TylerH
122

Solusi yang selalu saya gunakan adalah memudar, lalu mengecilkan font-size, paddingdan marginnilai - nilai. Itu tidak terlihat sama dengan penghapusan, tetapi bekerja tanpa statis heightatau max-height.

Contoh kerja:

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

Steven Vachon
sumber
Bekerja dengan rapi untuk saya. Tidak seperti slideUp / Down jQuery. Anda dapat melihat perbedaan hanya dengan CPU yang lemah, seperti komputer atau ponsel lama, dan membuka dan menutup banyak dari mereka secara bersamaan.
Cruz Nunez
3
Jika Anda memiliki tombol atau elemen non-teks lainnya, Anda akan berakhir dengan spasi putih yang tidak diinginkan saat tidak melayang.
Dennis W
3
Anda dapat memperbaikinya lebih lanjut dengan memilih semua elemen anak dengan *dan menerapkan perubahan lainnya. Namun, tombol seharusnya terpengaruh oleh kode saya di atas, jika ditata dengan benar em.
Steven Vachon
1
Dalam kasus saya, saya juga perlu menambahkan line-height: 0;danborder-width: 0;
Andrey Shatilov
1
Anda tidak perlu menyesuaikan line-heightjika Anda benar menghindari nilai pada unit: developer.mozilla.org/en-US/docs/Web/CSS/…
Steven Vachon
93

Saya tahu ini adalah jawaban ketiga puluh untuk pertanyaan ini, tetapi saya pikir itu sepadan, jadi begini. Ini adalah solusi khusus CSS dengan properti berikut:

  • Tidak ada penundaan di awal, dan transisi tidak berhenti lebih awal. Di kedua arah (meluas dan menciut), jika Anda menentukan durasi transisi 300 ms dalam CSS Anda, maka transisi membutuhkan 300 ms, titik.
  • Ini mentransisikan ketinggian sebenarnya (tidak seperti transform: scaleY(0)), jadi itu melakukan hal yang benar jika ada konten setelah elemen dilipat.
  • Sementara (seperti solusi lain) ada yang angka ajaib (seperti "memilih panjang yang lebih tinggi dari kotak Anda pernah akan menjadi"), itu tidak fatal jika asumsi Anda berakhir sampai menjadi salah. Transisi mungkin tidak terlihat luar biasa dalam kasus itu, tetapi sebelum dan setelah transisi, ini bukan masalah: Dalam keadaan diperluas ( height: auto), seluruh konten selalu memiliki ketinggian yang benar (tidak seperti misalnya jika Anda memilih max-heightyang ternyata menjadi terlalu rendah). Dan dalam keadaan runtuh, ketinggiannya nol seperti seharusnya.

Demo

Berikut ini demo dengan tiga elemen yang dapat dilipat, semua ketinggian berbeda, yang semuanya menggunakan CSS yang sama. Anda mungkin ingin mengklik "halaman penuh" setelah mengklik "jalankan snippet". Perhatikan bahwa JavaScript hanya mengaktifkan collapsedkelas CSS, tidak ada pengukuran yang terlibat. (Anda dapat melakukan demo ini tanpa JavaScript sama sekali dengan menggunakan kotak centang atau :target). Perhatikan juga bahwa bagian dari CSS yang bertanggung jawab untuk transisi cukup singkat, dan HTML hanya membutuhkan satu elemen pembungkus tambahan.

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

Bagaimana cara kerjanya?

Sebenarnya ada dua transisi yang terlibat dalam mewujudkan hal ini. Salah satunya transisi margin-bottomdari 0px (dalam status diperluas) ke -2000pxdalam kondisi diciutkan (mirip dengan jawaban ini ). 2000 di sini adalah angka ajaib pertama, didasarkan pada asumsi bahwa kotak Anda tidak akan lebih tinggi dari ini (2000 piksel sepertinya pilihan yang masuk akal).

Menggunakan margin-bottomtransisi sendiri dengan sendirinya memiliki dua masalah:

  • Jika Anda benar-benar memiliki kotak yang lebih tinggi dari 2000 piksel, maka margin-bottom: -2000pxtidak akan menyembunyikan semuanya - akan ada barang yang terlihat bahkan dalam kasing yang runtuh. Ini adalah perbaikan kecil yang akan kami lakukan nanti.
  • Jika kotak aktual, katakanlah, 1000 piksel tinggi, dan transisi Anda panjang 300 ms, maka transisi yang terlihat sudah berakhir setelah sekitar 150 ms (atau, dalam arah yang berlawanan, mulai terlambat 150 ms).

Memperbaiki masalah kedua ini adalah tempat transisi kedua masuk, dan transisi ini secara konseptual menargetkan tinggi minimum pembungkus ("secara konseptual" karena kita tidak benar-benar menggunakan min-heightproperti untuk ini; lebih lanjut tentang itu nanti).

Berikut ini animasi yang menunjukkan bagaimana menggabungkan transisi margin bawah dengan transisi ketinggian minimum, keduanya memiliki durasi yang sama, memberi kita transisi gabungan dari tinggi penuh ke tinggi nol yang memiliki durasi yang sama.

animasi seperti yang dijelaskan di atas

Bilah kiri menunjukkan bagaimana margin bawah negatif mendorong bagian bawah ke atas, mengurangi ketinggian yang terlihat. Bilah tengah menunjukkan bagaimana ketinggian minimum memastikan bahwa dalam kasus runtuh, transisi tidak berakhir lebih awal, dan dalam kasus ekspansi, transisi tidak dimulai terlambat. Bilah kanan menunjukkan bagaimana kombinasi keduanya menyebabkan kotak untuk transisi dari ketinggian penuh ke ketinggian nol dalam jumlah waktu yang benar.

Untuk demo saya, saya telah menetapkan 50px sebagai nilai tinggi minimum atas. Ini adalah angka ajaib kedua, dan itu harus lebih rendah dari ketinggian kotak yang pernah ada. 50px tampaknya masuk akal juga; tampaknya tidak mungkin Anda sering ingin membuat elemen yang dapat dilipat yang bahkan tidak setinggi 50 piksel.

Seperti yang Anda lihat dalam animasi, transisi yang dihasilkan adalah kontinu, tetapi tidak dapat dibedakan - pada saat tinggi minimum sama dengan tinggi penuh yang disesuaikan dengan margin bawah, ada perubahan kecepatan yang tiba-tiba. Ini sangat nyata dalam animasi karena menggunakan fungsi pewaktuan linear untuk kedua transisi, dan karena keseluruhan transisi sangat lambat. Dalam kasus aktual (demo saya di atas), transisi hanya membutuhkan 300 ms, dan transisi margin bawah tidak linier. Saya telah bermain-main dengan banyak fungsi pengaturan waktu yang berbeda untuk kedua transisi, dan yang akhirnya saya rasakan sepertinya mereka bekerja paling baik untuk berbagai kasus terluas.

Masih ada dua masalah yang harus diperbaiki:

  1. titik dari atas, di mana kotak-kotak dengan ketinggian lebih dari 2000 piksel tidak sepenuhnya tersembunyi dalam keadaan runtuh,
  2. dan masalah sebaliknya, di mana dalam kasus non-tersembunyi, kotak dengan tinggi kurang dari 50 piksel terlalu tinggi bahkan ketika transisi tidak berjalan, karena ketinggian minimum membuat mereka di 50 piksel.

Kami memecahkan masalah pertama dengan memberikan elemen wadah a max-height: 0dalam kasus runtuh, dengan 0s 0.3stransisi. Ini berarti bahwa itu bukan transisi, tetapi max-heightditerapkan dengan penundaan; itu hanya berlaku setelah transisi selesai. Agar ini berfungsi dengan benar, kita juga perlu memilih numerik max-heightuntuk keadaan sebaliknya, yang tidak diciutkan. Tetapi tidak seperti dalam kasus 2000px, di mana memilih nomor yang terlalu besar mempengaruhi kualitas transisi, dalam kasus ini, itu benar-benar tidak masalah. Jadi kita bisa memilih angka yang begitu tinggi sehingga kita tahu bahwa tidak ada ketinggian yang akan mendekati ini. Saya memilih satu juta piksel. Jika Anda merasa Anda perlu mendukung konten dengan ketinggian lebih dari satu juta piksel, maka 1) Saya minta maaf, dan 2) tambahkan saja beberapa nol.

Masalah kedua adalah alasan mengapa kita tidak benar-benar menggunakan min-heightuntuk transisi ketinggian minimum. Sebaliknya, ada ::afterpseudo-elemen dalam wadah dengan heighttransisi dari 50px ke nol. Ini memiliki efek yang sama dengan min-height: Ini tidak akan membiarkan wadah menyusut di bawah tinggi apa pun yang dimiliki elemen pseudo saat ini. Tetapi karena kita menggunakan height, bukan min-height, kita sekarang dapat menggunakan max-height(sekali lagi diterapkan dengan penundaan) untuk mengatur tinggi aktual pseudo-elemen menjadi nol setelah transisi selesai, memastikan bahwa setidaknya di luar transisi, bahkan elemen kecil memiliki ketinggian yang benar. Karena min-heightini lebih kuat daripada max-height, ini tidak akan bekerja jika kita menggunakan wadah ini min-heightbukan pseudo-elemenheight. Sama seperti max-heightpada paragraf sebelumnya, ini max-heightjuga membutuhkan nilai untuk kebalikan dari transisi. Tetapi dalam hal ini kita bisa memilih 50px.

Diuji di Chrome (Win, Mac, Android, iOS), Firefox (Win, Mac, Android), Edge, IE11 (kecuali untuk masalah tata letak flexbox dengan demo saya bahwa saya tidak mengganggu debugging), dan Safari (Mac, iOS ). Berbicara tentang flexbox, seharusnya dimungkinkan untuk membuatnya bekerja tanpa menggunakan flexbox apa pun; sebenarnya saya pikir Anda bisa membuat hampir semuanya berfungsi di IE7 - kecuali kenyataan bahwa Anda tidak akan memiliki transisi CSS, menjadikannya latihan yang agak tidak berguna.

balpha
sumber
36
Saya harap Anda dapat mempersingkat (menyederhanakan) solusi Anda, atau setidaknya contoh kode - sepertinya 90% contoh kode tidak relevan dengan jawaban Anda.
Gil Epshtain
Apakah ada cara untuk membuat transisi ini juga berfungsi jika collapsible-wrappermemiliki posisi absolut. Pada overflow: hiddeninduk diperlukan untuk transisi tetapi mengganggu elemen-elemen yang benar-benar diposisikan.
pmkro
1
@ pmkro Ya, saya juga punya masalah itu. Saya menyelesaikannya dengan menggunakan clip-path: polygon(...)bukan overflow: hidden, karena tidak seperti yang terakhir, Anda dapat mentransisikan yang pertama. Sebagai fallback untuk browser lama saya menggunakan transformasi penskalaan tambahan. Lihat komentar di bagian atas github.com/StackExchange/Stacks/blob/develop/lib/css/components/…
balpha
2
Bagus. Ini bekerja dengan sangat baik. Seharusnya jawaban yang diterima
Henry Ing-Simmons
84

Anda bisa, dengan sedikit jiggery-pokery non-semantik. Pendekatan saya yang biasa adalah untuk menghidupkan tinggi DIV luar yang memiliki anak tunggal yang merupakan DIV tanpa gaya yang hanya digunakan untuk mengukur tinggi konten.

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>

Orang ingin hanya dapat membuang .measuringWrapperdan hanya mengatur tinggi DIV ke otomatis dan menghidupkannya, tetapi itu sepertinya tidak berhasil (ketinggiannya diatur, tetapi tidak ada animasi terjadi).

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>

Interpretasi saya adalah bahwa ketinggian eksplisit diperlukan untuk menjalankan animasi. Anda tidak bisa mendapatkan animasi tentang ketinggian ketika salah satu ketinggian (awal atau akhir tinggi) auto.

jhurshman
sumber
10
Karena ini bergantung pada javascript, Anda juga bisa dengan mudah menambahkan measuringWrapper menggunakan javascript juga!
Quickredfox
18
Anda bisa melakukannya tanpa bungkus. Hanya: function growDiv () {var growDiv = document.getElementById ('grow'); if (growDiv.clientHeight) {growDiv.style.height = 0; } else {growDiv.style.height = growDiv.scrollHeight + 'px'; }}
user1742529
8
Lihat ini ... bicarakan jawaban sederhana jsfiddle.net/n5XfG/2596 ... Jawaban Anda sangat kompleks tanpa alasan yang jelas. Tidak perlu max-height, tidak perlu auto, dan terutama tidak perlu Javascript !! Hanya dua deklarasi sederhana
VIDesignz
12
@VIDesignz Anda menghidupkan lebih dari margin: 100%. Ini 100% dari lebar elemen, bukan tingginya! Ini berarti, jika Anda memiliki elemen dengan tinggi lebih besar dari lebarnya, ini tidak akan menyembunyikannya. Juga, kecepatan animasi yang sebenarnya sama sekali berbeda dari yang ditentukan.
Timo Türschmann
3
Saya senang dengan jawaban VIDesignz sampai saya membaca lebih banyak tentang komentar Timo. Ya, margin-top(dan margin-bottom) relatif terhadap lebar ketika didefinisikan dalam persentase, ya itu bodoh, tetapi itu juga menjelaskan mengapa timing animasi buka dan tutup benar-benar berbeda - itu adalah hal yang sama seperti yang Anda lihat dalam jawaban berperingkat teratas, menentukan hard -tinggi max yang dikodekan. Mengapa ini begitu sulit dilakukan dengan benar?
Coderer
52

Solusi visual untuk menjiwai ketinggian menggunakan transisi CSS3 adalah dengan menghidupkan padding.

Anda tidak cukup mendapatkan efek penghapusan penuh, tetapi bermain-main dengan durasi transisi dan nilai padding akan membuat Anda cukup dekat. Jika Anda tidak ingin mengatur ketinggian / maks-tinggi secara eksplisit, ini yang Anda cari.

div {
    height: 0;
    overflow: hidden;
    padding: 0 18px;
    -webkit-transition: all .5s ease;
       -moz-transition: all .5s ease;
            transition: all .5s ease;
}
div.animated {
    height: auto;
    padding: 24px 18px;
}

http://jsfiddle.net/catharsis/n5XfG/17/ (riffed off stephband di atas jsFiddle)

Pembersihan
sumber
3
Saya pikir ini adalah jawaban terbaik. Teknik ini dapat diperluas untuk menyesuaikan bantalan pada anak-anak juga. Dalam kasus saya, saya dapat menggabungkannya dengan transisi ketinggian secara eksplisit pada beberapa konten yang diungkapkan, dan efek totalnya jauh lebih berhasil daripada max-height work-around, yang bagus untuk pengungkapan tetapi memperkenalkan momen canggung dari menunda bersembunyi. Saya lebih cepat tidak menghidupkan sama sekali daripada memperkenalkan penundaan yang tidak berarti yang membuat aplikasi saya tampak tidak responsif. Saya terkejut begitu banyak orang tampaknya berpikir itu dapat diterima.
Titik koma
17
Kecuali bahwa di sini Anda tidak menjiwai ketinggian sama sekali. Anda menghidupkan padding ... itu bisa menghilang dengan baik karena dapat menghidupkan dari keadaan saat ini ke 0, tetapi jika Anda perhatikan dengan seksama ketika meluas itu muncul terbuka dengan teks dan kemudian padding hanya menjiwai .. karena itu tidak tahu cara menghidupkan dari 0 ke otomatis .... diperlukan rentang numerik ... begitulah cara tweening bekerja.
Rob R
Ini adalah solusi yang baik yang tidak diretas. Ini bukan jawaban terbaik untuk pertanyaan ini , tetapi ini merupakan alternatif yang bekerja untuk saya. Kadang-kadang Anda hanya perlu efek beberapa animasi ketinggian, bukan animasi penuh :)
Ivan Durst
Solusi ini juga gagal saat menggunakan penundaan transisi.
Michel Joanisse
Saya juga setuju bahwa solusi ini adalah solusi bersih yang memberikan transisi yang cukup lancar jika animasi Anda cukup cepat (dalam kasus saya untuk akordeon dengan transisi 0,1 itu sempurna!). Ini tidak cocok dengan banyak aplikasi, tetapi tidak akan ada jawaban lain untuk pertanyaan ini!
Remi D
46

Solusi saya adalah dengan mentransisikan max-height ke ketinggian konten yang tepat untuk animasi yang bagus dan halus, kemudian gunakan transisi. Kembali ke panggilan untuk mengatur max-height ke 9999px sehingga konten dapat mengubah ukuran secara bebas.

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>

Adam
sumber
14
@ Derija93 Itu menggunakan animasi batas waktu javascript biasa. Tantangannya adalah menggunakan transisi CSS3 sebagai gantinya.
Adam
3
Baiklah. Tetapi mengapa Anda menggunakan "transisi CSS3" jika Anda, dalam contoh Anda, sudah menggunakan jQuery, perpustakaan, yang menyediakan banyak kode "tulis lebih sedikit, lakukan lebih banyak"? Saya ingin menunjukkan bahwa versi Anda mungkin terlihat jauh lebih baik, meskipun lebih rumit, jika BUKAN menggunakan jQuery sehingga dapat berjalan di hampir semua situs web. Saya kira saya salah mengucapkannya. Maaf soal itu. ;)
Kiruse
27
@ Derija93 Mungkin karena transisi CSS3 memiliki (menurut semua sumber saya dapat menemukan) kinerja yang jauh lebih baik daripada animasi jQuery. (Sebenarnya sangat penting untuk kasus penggunaan saya saat ini, yang membawa saya ke sini.)
Mark Amery
4
@ Derija93 Karena animasi Javascript berjalan lambat dibandingkan dengan transisi transisi CSS3, dan dengan animasi jQuery Anda harus khawatir tentang loop animasi. Hidupkan sesuatu di klik, lalu klik dengan cepat dan tonton animasi berulang. Ini ditangani dengan CSS3.
AlbertEngelB
2
@ Dropped.on.Caprica Ini sudah agak tua sekarang. Saya sudah mengatakan saya salah memahami konsep yang dia coba tunjukkan. Anyways, untuk animasi sederhana, .stopmelakukan trik untuk masalah loop animasi yang agak rumit. Sekarang ketika Anda menghidupkan tinggi dan warna tetapi ingin mengganggu animasi ketinggian saja, segalanya menjadi sedikit lebih rumit ... Saya mengerti maksud Anda.
Kiruse
43

Jawaban yang diterima berfungsi untuk sebagian besar kasus, tetapi tidak berfungsi dengan baik ketika Anda divdapat sangat bervariasi dalam ketinggian - kecepatan animasi tidak tergantung pada ketinggian konten yang sebenarnya, dan itu bisa terlihat berombak.

Anda masih dapat melakukan animasi sebenarnya dengan CSS, tetapi Anda harus menggunakan JavaScript untuk menghitung ketinggian item, alih-alih mencoba menggunakannya auto. Tidak diperlukan jQuery, meskipun Anda mungkin harus sedikit memodifikasi ini jika Anda ingin kompatibilitas (berfungsi di Chrome versi terbaru :)).

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>

Oleg Vaskevich
sumber
Ini mungkin membantu, tetapi saya tidak tahu karena saya tidak tahu bagaimana menggunakannya tanpa contoh yang lebih baik.
Ivan Durst
1
Anda hanya melewatkan elemen DOM (misalnya, dari document.getElementById('mydiv')atau $('#mydiv').get()), dan fungsinya beralih antara menyembunyikan / menampilkannya. Jika Anda mengatur transisi CSS, elemen tersebut akan hidup secara otomatis.
Oleg Vaskevich
Saya menambahkan cuplikan. Ini memiliki keuntungan bekerja dengan baik untuk konten berukuran dinamis.
Oleg Vaskevich
3
-1, karena ini bukan "menggunakan CSS". Inti dari pertanyaan ini adalah untuk solusi bebas JS. Saya pikir jawaban "benar", itu bukan hack, akan menjadi ini, meskipun ...
dudewad
16
Downvote untuk menggunakan JS - dengan serius? Separuh jawaban di sini menggunakan JS, jadi downvote Anda sepertinya tidak adil atau tidak perlu. Selain itu, jawaban ini masih menggunakan CSS untuk melakukan animasi yang sebenarnya, yang merupakan inti dari OP. Satu-satunya hal yang digunakan JS adalah menghitung tinggi sebenarnya, karena tidak mungkin melakukannya dengan CSS murni (dan pengaturan min-heightseperti pada jawaban yang diharapkan menyebabkan masalah dengan kecepatan animasi ketika ukuran daftar dapat sangat bervariasi).
Oleg Vaskevich
30

Ada sedikit penyebutan Element.scrollHeightproperti yang dapat berguna di sini dan masih dapat digunakan dengan transisi CSS murni. Properti selalu mengandung ketinggian "penuh" dari suatu elemen, terlepas dari apakah dan bagaimana kontennya meluap sebagai hasil dari ketinggian yang diciutkan (misalnya height: 0).

Dengan demikian, untuk height: 0elemen (secara efektif runtuh), tingginya "normal" atau "penuh" masih tersedia melalui scrollHeightnilainya (selalu panjang pixel ).

Untuk elemen seperti itu, anggap sudah memiliki transisi yang diatur seperti misalnya (menggunakan ulsesuai pertanyaan awal):

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

Kami dapat memicu "perluasan" animasi yang diinginkan, hanya menggunakan CSS, dengan sesuatu seperti berikut (di sini asumsi ulvariabel merujuk ke daftar):

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

Itu dia. Jika Anda perlu menciutkan daftar, salah satu dari dua pernyataan berikut akan dilakukan:

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

Kasus penggunaan khusus saya berkisar seputar daftar panjang yang tidak diketahui dan seringkali cukup panjang, jadi saya merasa tidak nyaman memilih "cukup besar" heightatau max-heightspesifikasi dan mempertaruhkan konten terputus atau konten yang tiba-tiba perlu Anda gulir (jika overflow: auto, misalnya) . Selain itu, pelonggaran dan waktu rusak dengan max-heightsolusi berbasis, karena ketinggian yang digunakan dapat mencapai nilai maksimum jauh lebih cepat daripada yang dibutuhkan untuk max-heightmencapai 9999px. Dan saat resolusi layar bertambah, panjang piksel seperti 9999pxmeninggalkan rasa tidak enak di mulut saya. Solusi khusus ini menyelesaikan masalah dengan cara yang elegan, menurut saya.

Akhirnya, di sini berharap bahwa revisi di masa depan dari kebutuhan penulis alamat CSS untuk melakukan hal-hal semacam ini bahkan lebih elegan - kembalilah pada gagasan nilai "dikomputasi" vs "terpakai" dan "diselesaikan", dan pertimbangkan apakah transisi harus berlaku untuk dikomputasi. nilai, termasuk transisi dengan widthdan height(yang saat ini mendapatkan sedikit perlakuan khusus).

amn
sumber
6
Anda tidak menemukannya di jawaban lain di sini karena berinteraksi dengan DOM menggunakan Element.scrollHeightproperti memerlukan JavaScript dan, seperti yang dinyatakan dalam pertanyaan, mereka ingin melakukan ini tanpa JavaScript.
TylerH
3
Ada banyak bagian lain dari CSS selain dari dua kelas semu yang dapat menyelesaikan masalah ini, seperti yang ditunjukkan oleh jawaban tertinggi pada halaman 1. Mengatur gaya dalam JavaScript bukan "CSS murni" karena ini mengharuskan JS untuk ditetapkan di tempat pertama. Seringkali ketika seseorang meminta solusi khusus CSS, itu karena mereka tidak dapat menyuntikkan JavaScript apa pun, atau tidak diizinkan oleh proyek atau peran mereka saat ini.
TylerH
29

Gunakan max-heightdengan pelonggaran dan penundaan transisi yang berbeda untuk setiap negara.

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

Lihat contoh: http://jsfiddle.net/0hnjehjc/1/

malihu
sumber
12
Masalahnya di sini adalah, untuk memastikan Anda memiliki ruang yang cukup dalam lingkungan yang dinamis, Anda perlu menggunakan ketinggian max konyol seperti 999999px. Ini, di sisi lain, akan menggeser animasi Anda, karena bingkai dihitung dari nilai ini. Jadi, Anda mungkin berakhir dengan animasi "delay" di satu arah dan akhir yang sangat cepat di arah lain (corr: timing-functions)
Julian F. Weinert
29

Tidak ada nilai kode keras.

Tanpa JavaScript.

Tidak ada perkiraan.

Caranya adalah dengan menggunakan yang disembunyikan & diduplikasi divuntuk membuat browser memahami apa arti 100%.

Metode ini cocok setiap kali Anda dapat menduplikasi DOM elemen yang ingin Anda menghidupkan.

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

Vivek Maharajh
sumber
Dilakukan dengan baik - ini adalah solusi yang valid untuk masalah yang seharusnya tidak ada. Animasi max-height adalah bas kecuali transisi diatur ke "linear", itu juga (jelas) sangat buruk untuk menganimasikan konten CMS di mana tinggi variabel.
M_Willett
ini pintar, tapi saya tidak akan senang menduplikasi elemen DOM dan konten untuk ini.
Andre Figueiredo
Anda dapat melakukan ini tanpa wadah dan lebih banyak pemain dengan menghidupkan transform: scaleY(1), karena transisi ini tidak menghilangkan ruang.
Fabian von Ellerts
21

Saat saya memposting ini sudah ada lebih dari 30 jawaban, tetapi saya merasa jawaban saya meningkat pada jawaban yang sudah diterima oleh jake.

Saya tidak puas dengan masalah yang timbul dari hanya menggunakan max-heightdan transisi CSS3, karena seperti banyak komentator mencatat, Anda harus mengatur max-heightnilai Anda sangat dekat dengan ketinggian sebenarnya atau Anda akan mendapatkan penundaan. Lihat JSFiddle ini untuk contoh masalah itu.

Untuk menyiasatinya (walaupun masih belum menggunakan JavaScript), saya menambahkan elemen HTML lain yang mentransisi nilai transform: translateYCSS.

Ini berarti keduanya max-heightdan translateYdigunakan: max-heightmemungkinkan elemen untuk menekan elemen di bawahnya, sambil translateYmemberikan efek "instan" yang kita inginkan. Masalah dengan max-heightmasih ada, tetapi efeknya berkurang. Ini berarti Anda dapat mengatur ketinggian yang jauh lebih besar untuk max-heightnilai Anda dan lebih sedikit mengkhawatirkannya.

Manfaat keseluruhan adalah bahwa pada transisi kembali (runtuh), pengguna melihat translateYanimasi segera, jadi tidak masalah berapa lama max-heightwaktu yang dibutuhkan.

Solusi sebagai Fiddle

body {
  font-family: sans-serif;
}

.toggle {
  position: relative;
  border: 2px solid #333;
  border-radius: 3px;
  margin: 5px;
  width: 200px;
}

.toggle-header {
  margin: 0;
  padding: 10px;
  background-color: #333;
  color: white;
  text-align: center;
  cursor: pointer;
}

.toggle-height {
  background-color: tomato;
  overflow: hidden;
  transition: max-height .6s ease;
  max-height: 0;
}

.toggle:hover .toggle-height {
  max-height: 1000px;
}

.toggle-transform {
  padding: 5px;
  color: white;
  transition: transform .4s ease;
  transform: translateY(-100%);
}

.toggle:hover .toggle-transform {
  transform: translateY(0);
}
<div class="toggle">
  <div class="toggle-header">
    Toggle!
  </div>
  <div class="toggle-height">
    <div class="toggle-transform">
      <p>Content!</p>
      <p>Content!</p>
      <p>Content!</p>
      <p>Content!</p>
    </div>
  </div>
</div>

<div class="toggle">
  <div class="toggle-header">
    Toggle!
  </div>
  <div class="toggle-height">
    <div class="toggle-transform">
      <p>Content!</p>
      <p>Content!</p>
      <p>Content!</p>
      <p>Content!</p>
    </div>
  </div>
</div>

Andrew Messier
sumber
Nice perbandingan @davidtaubmann, pena Anda menggambarkan perbedaan dengan sangat baik! Aku pergi dengan translateYlebih scalekarena saya tidak seperti bagaimana scalememberi efek kompresi.
Andrew Messier
Terima kasih @ andrew-messier, saya menghapus komentar karena ada kesalahan, terjemahanYa tidak mengeksekusi di codepen.io/davidtaubmann/pen/zKZvGP (karena tidak ada anak untuk melakukan perpindahan, perlu diperbaiki) ... tetapi dalam hal ini kita dapat dengan sempurna melihat perbandingan dari ONLY MAX-HEIGHT dan mencampurnya dengan skala (seperti yang dinyatakan pada jawaban lain): codepen.io/davidtaubmann/pen/jrdPER . Ini semua banyak membantu saya dengan metodologi Target yang saya gunakan
DavidTaubmann
18

Ok, jadi saya pikir saya datang dengan jawaban yang sangat sederhana ... tidak max-height, menggunakan relativepositioning, bekerja pada lielemen, & adalah CSS murni. Saya belum menguji apa pun selain Firefox, meskipun dilihat dari CSS, itu harus bekerja di semua browser.

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>
VIDesignz
sumber
13
Ini akan bekerja sampai ketinggian elemen melebihi lebarnya. Ini adalah dasar bagaimana margin dihitung menggunakan persentase: mereka dihitung berdasarkan lebar elemen. Jadi jika Anda memiliki elemen lebar 1000 px, maka elemen di 1100 px akan terlalu besar untuk solusi ini untuk bekerja, artinya Anda harus meningkatkan margin atas negatif. Pada dasarnya, ini adalah masalah yang sama persis seperti menggunakan tinggi atau maks-tinggi.
dudewad
15

Suntingan: Gulir ke bawah untuk jawaban yang diperbarui.
Saya membuat daftar drop-down dan melihat posting ini ... banyak jawaban yang berbeda tetapi saya memutuskan untuk berbagi daftar drop-down saya juga, ... Itu tidak sempurna tetapi setidaknya itu akan menggunakan hanya css untuk jatuhkan! Saya telah menggunakan transform: translateY (y) untuk mengubah daftar menjadi tampilan ...
Anda dapat melihat lebih banyak di tes
http://jsfiddle.net/BVEpc/4/
Saya telah menempatkan div di belakang setiap li karena saya daftar drop-down datang dari atas dan untuk menunjukkan kepada mereka dengan benar ini diperlukan, kode div saya adalah:

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

dan melayang adalah:

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

dan karena ketinggian ul diatur ke konten itu bisa mendapatkan lebih dari konten tubuh Anda itu sebabnya saya melakukan ini untuk ul:

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

dan arahkan:

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

kedua kalinya setelah transisi adalah penundaan dan itu akan disembunyikan setelah daftar drop-down saya ditutup secara animasi ...
Semoga nanti ada orang yang mendapat manfaat dari ini.

EDIT: Saya tidak percaya ppl benar-benar menggunakan prototipe ini! menu tarik turun ini hanya untuk satu sub menu dan itu saja !! Saya telah memperbarui yang lebih baik yang dapat memiliki dua sub menu untuk ltr dan rtl direction dengan dukungan IE 8.
Fiddle for LTR
Fiddle for RTL
mudah-mudahan seseorang menemukan ini berguna di masa depan.

Sijav
sumber
11

Anda dapat bertransisi dari ketinggian: 0 ke tinggi: dengan ketentuan otomatis bahwa Anda juga menyediakan tinggi-min dan tinggi-max.

div.stretchy{
    transition: 1s linear;
}

div.stretchy.hidden{
    height: 0;
}

div.stretchy.visible{
    height: auto;
    min-height:40px;
    max-height:400px;
}
Stuart Badminton
sumber
@Stuart Badminton dapatkah Anda memberikan contoh kerja? Saya telah menyatukan ini tetapi sepertinya tidak berhasil di mana saja :( jsfiddle.net/gryzzly/n5XfG
Misha Reyzlin
5
Masalahnya dengan aturan transisi Anda. untuk membuatnya bekerja, Anda perlu menerapkan transisi ke min dan max tinggi juga. transisi: tinggi .5s linier, min-tinggi .5s linier, max-tinggi .5s linier
Stuart Badminton
2
inilah yang saya dapatkan nanti, seperti yang Anda katakan, diperlukan untuk menghidupkan max-height: jsfiddle.net/gryzzly/n5XfG/3
Misha Reyzlin
11
Tentu saja, ada masalah dengan ini. Waktu yang diperlukan untuk menghidupkan max-height bukanlah waktu yang diperlukan untuk transisi ke ketinggian otomatis kotak: ia tiba di ketinggian: otomatis terlebih dahulu, sebelum max-height selesai dianimasikan. Demikian pula, ketika beralih ke 0, transisi tidak segera dimulai, karena ketinggian maksimum dimulai pada ketinggian yang lebih besar dari ketinggian: otomatis. Transisi ke ketinggian maksimal: 1000px memperjelas ini: jsfiddle.net/n5XfG/11
stephband
Anda benar, pada pengujian lebih lanjut saya melihat ini. Saya tidak tahu apakah ketinggian penuh: 0 ke tinggi: otomatis akan pernah diterapkan tetapi menggunakan max-height dalam beberapa situasi tidak menyelesaikan situasi yang mustahil dilakukan hanya dengan menggunakan CSS.
Stuart Badminton
10

Solusi Flexbox

Pro:

  • sederhana
  • tidak ada JS
  • transisi yang mulus

Cons:

  • elemen harus dimasukkan ke dalam wadah flex tinggi tetap

Cara kerjanya adalah dengan selalu memiliki basis-fleksibel: otomatis pada elemen dengan konten, dan mentransisikan flex-grow dan flex-shrink sebagai gantinya.

Sunting: Peningkatan JS Fiddle terinspirasi oleh antarmuka Xbox One.

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

Lee Comstock
sumber
7

Memperluas jawaban @ jake, transisi akan mencapai nilai tinggi max, menyebabkan animasi yang sangat cepat - jika Anda mengatur transisi untuk keduanya: hover dan off Anda kemudian dapat mengontrol kecepatan gila sedikit lebih.

Jadi li: hover adalah ketika mouse memasuki negara dan kemudian transisi pada properti non-melayang akan menjadi cuti mouse.

Semoga ini bisa membantu.

misalnya:

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

Ini biola: http://jsfiddle.net/BukwJ/

jamie
sumber
1
Saya tidak tahu mengapa ini mendapat -1. Saya benar-benar berpikir ini adalah upaya yang lebih baik daripada beberapa orang menambahkan banyak javascript. Ini bukan solusi yang sempurna, tetapi dengan beberapa penyesuaian itu melakukan pekerjaan dengan baik, saya menemukan ini bekerja untuk nilai pengembalian. transisi: semua 500ms kubik-bezier (0,000, 1,225, 0,085, 0,385); Ini didasarkan pada transisi 2s pada pembukaan kemudian kode di atas untuk kembali ke keadaan awal. Terima kasih ... Ini membantu saya lebih baik daripada semua yang di atas. +1 Saya menggunakan situs ini untuk membuat bezier matthewlein.com/ceaser
gcoulby
OK butuh sedikit lebih banyak penyesuaian. transisi: semua 500ms kubik-bezier (0,000, 1,390, 0,000, 0,635); Saya harus menentukan transisi saya mulai dari 5% -100% (tetapi dalam kenyataannya nilai akhir adalah sekitar 28%) sehingga tergantung pada proyek.
gcoulby
Tentu saja, ini tidak ideal, tetapi ini adalah perbaikan cepat jika Anda tahu apa yang akan menjadi tinggi rata-rata.
jamie
7

Saya pikir saya datang dengan solusi yang sangat solid

BAIK! Saya tahu masalah ini setua internet, tapi saya pikir saya punya solusi yang saya berubah menjadi plugin yang disebut transisi-mutan . Solusi saya menetapkan style=""atribut untuk elemen yang dilacak setiap kali ada perubahan dalam DOM. hasil akhirnya adalah bahwa Anda dapat menggunakan CSS baik untuk transisi Anda dan tidak menggunakan perbaikan hacky atau javascript khusus. Satu-satunya hal yang harus Anda lakukan adalah mengatur apa yang ingin Anda lacak pada elemen yang digunakan data-mutant-attributes="X".

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

Itu dia! Solusi ini menggunakan MutationObserver untuk mengikuti perubahan di DOM. Karena itu, Anda tidak perlu mengatur apa pun atau menggunakan javascript untuk menghidupkan benda secara manual. Perubahan dilacak secara otomatis. Namun, karena menggunakan MutationObserver, ini hanya akan transisi di IE11 +.

Biola

JonTroncoso
sumber
12
Biasanya, ketika seseorang bertanya bagaimana melakukan sesuatu "tanpa JavaScript", itu berarti solusinya harus bekerja pada browser yang menonaktifkan JavaScript. Itu tidak berarti "tanpa menulis skrip saya sendiri". Jadi bisa dikatakan bahwa plugin Anda dapat digunakan tanpa menggunakan JavaScript adalah menyesatkan terbaik - mengingat itu adalah plugin JavaScript.
BoltClock
Saya harus mengklarifikasi, Ketika saya mengatakan Anda tidak harus menggunakan javascript khusus, maksud saya Anda tidak perlu menulis javascript apa pun. cukup sertakan perpustakaan JS dan tentukan atribut mana yang ingin Anda tonton dalam HTML. Anda tidak harus menggunakan css ketinggian tetap, atau mencari tahu apa-apa. hanya gaya dan pergi.
JonTroncoso
"(...) Anda tidak perlu mengatur apa pun atau menggunakan javascript untuk menghidupkan benda secara manual (...)" jadi Anda menggunakan JavaScript untuk bersenang
Roko C. Buljan
6

Berikut cara untuk beralih dari ketinggian mulai, termasuk 0, ke otomatis (ukuran penuh dan fleksibel) tanpa memerlukan kode hard-set pada basis per-simpul atau kode pengguna apa pun untuk menginisialisasi: https://github.com/csuwildcat / transisi-otomatis . Ini pada dasarnya adalah cawan suci untuk apa yang Anda inginkan, saya percaya -> http://codepen.io/csuwldcat/pen/kwsdF . Cukup tampar file JS berikut ke halaman Anda, dan yang perlu Anda lakukan setelah itu adalah menambah / menghapus atribut boolean tunggal - reveal=""- dari node yang ingin Anda kembangkan dan kontrak.

Inilah yang perlu Anda lakukan sebagai pengguna, setelah Anda memasukkan blok kode yang ditemukan di bawah kode contoh:

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

Berikut ini blok kode untuk dimasukkan dalam halaman Anda, setelah itu, semuanya adalah saus:

Letakkan file JS ini di halaman Anda - semuanya Just Works ™

/ * Kode untuk tinggi: otomatis; transisi * /

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

/ * Kode untuk DEMO * /

    document.addEventListener('click', function(e){
      if (e.target.nodeName == 'BUTTON') {
        var next = e.target.nextElementSibling;
        next.hasAttribute('reveal') ? next.removeAttribute('reveal') : next.setAttribute('reveal', '');
      }
    }, false);
csuwldcat
sumber
9
Walaupun ini adalah solusi yang jauh lebih bersih dan fleksibel daripada yang lain yang telah disarankan, saya pribadi percaya ini seharusnya tidak menjadi sesuatu yang harus disentuh JS sama sekali. Tidak mengatakan Anda salah, itu hanya desahan.
mystrdat
@ mystrdat menjadi jelas, JS hanya digunakan untuk melihat kondisi tertentu dan menambahkan beberapa atribut / nilai CSS sementara berdasarkan peristiwa / kondisi yang ditontonnya. Transisi masih semua dilakukan dalam CSS. Meskipun saya setuju, sayangnya tingkat pengaturan dan pegangan ini diperlukan untuk benar-benar memuaskan kasus penggunaan yang tampaknya sederhana! : /
csuwldcat
1
@KarolisRamanauskas tidak, itu bukan masalah - IE mendukung kedua CSS Keyframes dan requestAnimationFrame. Saya menggunakan clipsebagai pemicu properti tiruan saya, dan untuk beberapa alasan IE berhenti mengizinkan klip untuk dianimasikan. Saya beralih ke opacity, dan semuanya bekerja lagi: codepen.io/csuwldcat/pen/FpzGa . Saya telah memperbarui kode dalam jawaban yang cocok.
csuwldcat
1
@csuwldcat Solusi yang sangat bagus, saya perhatikan bahwa konten muncul dan menghilang sedikit, mengapa ini terjadi? Apakah ini bisa dihindari?
Beto Aveiga
12
Saya ingin memperbaiki ini, tetapi alih-alih menjawab pertanyaan tentang cara membuatnya berfungsi, Anda membagikan sebuah plugin yang Anda tulis untuk membuatnya berfungsi. Kami, yang penasaran, dibiarkan merekayasa balik plugin Anda, yang tidak terlalu menyenangkan. Saya berharap Anda akan memperbarui jawaban Anda untuk berisi lebih banyak penjelasan tentang apa yang dilakukan plugin Anda dan mengapa. Ubah kode menjadi lebih jelas. Misalnya, Anda memiliki seluruh bagian kode yang hanya menulis CSS statis. Saya lebih suka melihat CSS, daripada kode yang menghasilkannya. Anda dapat meninggalkan bagian yang membosankan, seperti mengulangi untuk semua awalan peramban.
gilly3
6

Jawaban Jake untuk menghidupkan max-height itu bagus, tetapi saya menemukan penundaan yang disebabkan oleh pengaturan max-height yang besar mengganggu.

Seseorang dapat memindahkan konten yang dapat diciutkan ke dalam div dalam dan menghitung ketinggian maks dengan mendapatkan ketinggian div dalam (melalui JQuery itu akan menjadi outerHeight ()).

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

Inilah tautan jsfiddle: http://jsfiddle.net/pbatey/duZpT

Inilah jsfiddle dengan jumlah minimal kode yang diperlukan: http://jsfiddle.net/8ncjjxh8/

pbatey
sumber
5

Saya menyadari bahwa utas ini semakin tua, tetapi peringkatnya tinggi pada pencarian Google tertentu, jadi saya pikir ini layak diperbarui.

Anda juga hanya mendapatkan / mengatur tinggi elemen sendiri:

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

Anda harus membuang Javascript ini segera setelah tag penutup target_box dalam tag skrip inline.

Charley
sumber
document.getElementById ('target_box'). getBoundingClientRect (). tinggi harus melakukan yang terbaik.
ubah
5

Saya bisa melakukan ini. Saya memiliki .child& a .parentdiv. Div anak sangat cocok dengan lebar / tinggi orang tua dengan absoluteposisi. Saya kemudian menghidupkan translateproperti untuk mendorong Ynilainya turun 100%. Animasi sangat halus, tidak ada gangguan atau sisi bawah seperti solusi lain di sini.

Sesuatu seperti ini, kode semu

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

Anda akan menentukan heightpada .parent, di px, %, atau cuti sebagai auto. Div ini kemudian menutup .childdiv saat slide turun.

Josh Ribakoff
sumber
Contoh kerja ini akan sangat dihargai.
Neurotransmitter
5

Saya mengeposkan jawaban dengan JavaScript dan turun undian, jadi jengkel dan mencoba lagi, dan telah memecahkannya dengan CSS saja!

Solusi ini menggunakan beberapa 'teknik':

  • padding-bottom:100%'retas' di mana persentase didefinisikan dalam hal lebar elemen saat ini. Info lebih lanjut tentang teknik ini.
  • float shrink-wrapping, (mengharuskan div tambahan untuk menerapkan hack cleat clearing)
  • penggunaan https://caniuse.com/#feat=css-writing-mode dan beberapa transformasi untuk membatalkannya (ini memungkinkan penggunaan retasan padding di atas dalam konteks vertikal)

Hasilnya adalah bahwa kita mendapatkan pergantian pemain hanya menggunakan CSS, dan satu fungsi transisi untuk mencapai transisi dengan lancar; cawan Suci!

Tentu saja, ada kekurangannya! Saya tidak tahu cara mengontrol lebar di mana konten terpotong ( overflow:hidden); karena retakan padding-bottom, lebar dan tinggi saling terkait erat. Mungkin ada jalan, jadi akan kembali ke sana.

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>

Eoghan
sumber
Kelemahan lain dari ini adalah Anda tidak dapat memindahkan kursor dari div "hoverme" ke daftar item untuk berinteraksi dengannya (seolah-olah alasan OP bertanya), jadi itu hanya berguna sebagai fungsi tooltip daripada fungsi , katakanlah, menu dengan submenu bersarang.
TylerH
Itu murni konsekuensi dari cara pertanyaan itu dirumuskan dan tidak terkait dengan teknik. Anda dapat mengubah pelatuk menjadi input[type="checkbox"]:checkedalih - alih :hoverjika Anda ingin (mis. Anda tidak ingin menggunakan JavaScript untuk menambahkan kelas apa pun)
EoghanM
Maksud saya, terlepas dari bagaimana pertanyaan dirumuskan, jika implementasi solusi sangat terbatas, mungkin harus disebutkan dalam jawaban solusi (atau lebih baik diperhitungkan ). Anda menyebutkan solusi ini adalah 'cawan suci' tetapi div yang dipindahtangankan bahkan tidak dapat dilayang-layang ... sepertinya bukan solusi akhir bagi saya.
TylerH
Hai @TylerH, maaf, saya melewatkan fakta bahwa pemicu pada pertanyaan awal mengelilingi daftar yang diperluas, jadi daftar itu harus tetap terbuka ketika melayang. Saya telah memperbarui jawaban saya untuk mencerminkan ini. Seperti yang saya sebutkan, bagaimana itu dipicu tidak semua yang erat, karena saya sedang menyajikan teknik baru yang sebelumnya tidak dianggap mungkin hanya dalam CSS (saya sudah mencari solusi selama beberapa tahun).
EoghanM
4

Inilah solusi yang saya gunakan dalam kombinasi dengan jQuery. Ini berfungsi untuk struktur HTML berikut:

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

dan fungsinya:

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

Anda kemudian dapat menggunakan fungsi klik untuk mengatur dan menghapus ketinggian menggunakan 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 }
HandiworkNYC.com
sumber
ini tidak muncul dengan benar dengan versi jquery terbaru
oliverbachmann
4

Saya baru-baru ini mentransisikan max-heightpada lielemen daripada pembungkus ul.

Alasannya adalah bahwa penundaan untuk kecil max-heightsjauh kurang terlihat (jika sama sekali) dibandingkan dengan besar max-heights, dan saya juga dapat mengatur saya max-heightnilai relatif terhadap font-sizesatu lidaripada beberapa sejumlah besar sewenang-wenang dengan menggunakan emsatau rems.

Jika ukuran font saya 1rem, saya akan mengatur saya max-heightke sesuatu seperti 3rem(untuk mengakomodasi teks yang dibungkus). Anda dapat melihat contoh di sini:

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

mindfullsilence
sumber
3

Saya belum membaca semuanya secara terperinci tetapi saya memiliki masalah ini baru-baru ini dan saya melakukan yang berikut:

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

Ini memungkinkan Anda untuk memiliki div yang pada awalnya menunjukkan konten hingga ketinggian 200px dan pada hover ukurannya menjadi setidaknya setinggi seluruh konten div. Div tidak menjadi 3000px tetapi 3000px adalah batas yang saya memaksakan. Pastikan untuk memiliki transisi pada non: hover, jika tidak, Anda mungkin mendapatkan render yang aneh. Dengan cara ini: hover mewarisi dari non: hover.

Transisi tidak berfungsi dari px ke% atau ke otomatis. Anda harus menggunakan satuan ukuran yang sama. Ini berfungsi baik untuk saya. Menggunakan HTML5 membuatnya sempurna ....

Ingatlah bahwa selalu ada pekerjaan di sekitar ...; )

Semoga seseorang menemukan ini berguna

work.stella84
sumber
3

Solusi max-height dari Jake bekerja dengan baik, jika nilai max-height hard-coded yang disediakan tidak jauh lebih besar dari tinggi sebenarnya (karena jika tidak ada penundaan dan masalah waktu yang tidak diinginkan). Di sisi lain jika nilai hard-kode secara tidak sengaja tidak lebih besar dari tinggi sebenarnya elemen tidak akan terbuka sepenuhnya.

Solusi CSS saja berikut ini juga membutuhkan ukuran kode keras yang harus lebih besar dari sebagian besar ukuran nyata yang terjadi. Namun solusi ini juga berfungsi jika ukuran sebenarnya dalam beberapa situasi lebih besar dari ukuran hard-coded. Jika itu terjadi, transisi mungkin akan melompat sedikit, tetapi tidak akan pernah meninggalkan elemen yang terlihat sebagian. Jadi solusi ini juga dapat digunakan untuk konten yang tidak dikenal, misalnya dari database, di mana Anda hanya tahu bahwa kontennya biasanya tidak lebih besar dari x piksel, tetapi ada pengecualian.

Gagasannya adalah menggunakan nilai negatif untuk margin-bottom (atau margin-top untuk animasi yang sedikit berbeda) dan untuk menempatkan elemen konten ke elemen tengah dengan overflow: tersembunyi. Margin negatif elemen konten sehingga mengurangi ketinggian elemen tengah.

Kode berikut menggunakan transisi pada margin-bottom dari -150px ke 0px. Ini saja berfungsi dengan baik selama elemen konten tidak lebih tinggi dari 150px. Selain itu menggunakan transisi pada max-height untuk elemen tengah dari 0px ke 100%. Ini akhirnya menyembunyikan elemen tengah jika elemen konten lebih tinggi dari 150px. Untuk max-height, transisi hanya digunakan untuk menunda penerapannya satu detik saat menutup, bukan untuk efek visual yang halus (dan karenanya dapat berjalan dari 0px hingga 100%).

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>

Nilai untuk margin bawah harus negatif dan sedekat mungkin dengan ketinggian sebenarnya dari elemen konten. Jika itu (nilai absoute) lebih besar ada masalah keterlambatan dan waktu yang sama seperti dengan solusi max-height, yang bagaimanapun dapat dibatasi selama ukuran kode keras tidak jauh lebih besar dari yang asli. Jika nilai absolut untuk margin-bottom lebih kecil dari tinggi sebenarnya tansition melompat sedikit. Dalam kasus apa pun setelah transisi, elemen konten ditampilkan atau dihapus sepenuhnya.

Untuk lebih jelasnya lihat posting blog saya http://www.taccgl.org/blog/css_transition_display.html#combined_height

Helmut Emmelmann
sumber
3

Anda bisa melakukan ini dengan membuat animasi terbalik (runtuh) dengan clip-path.

#child0 {
    display: none;
}
#parent0:hover #child0 {
    display: block;
    animation: height-animation;
    animation-duration: 200ms;
    animation-timing-function: linear;
    animation-fill-mode: backwards;
    animation-iteration-count: 1;
    animation-delay: 200ms;
}
@keyframes height-animation {
    0% {
        clip-path: polygon(0% 0%, 100% 0.00%, 100% 0%, 0% 0%);
    }
    100% {
        clip-path: polygon(0% 0%, 100% 0.00%, 100% 100%, 0% 100%);
    }
}
<div id="parent0">
    <h1>Hover me (height: 0)</h1>
    <div id="child0">Some content
        <br>Some content
        <br>Some content
        <br>Some content
        <br>Some content
        <br>Some content
        <br>
    </div>
</div>

Andrii
sumber
2

Ini bukan "solusi" untuk masalah ini, tetapi lebih dari solusi. Ini hanya berfungsi seperti yang ditulis dengan teks, tetapi dapat diubah untuk bekerja dengan elemen lain sesuai kebutuhan saya yakin.

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

Berikut ini sebuah contoh: http://codepen.io/overthemike/pen/wzjRKa

Pada dasarnya, Anda mengatur ukuran font ke 0 dan transisi yang bukan ketinggian, atau max-tinggi, atau scaleY () dll. Pada kecepatan yang cukup cepat untuk mendapatkan ketinggian untuk mengubah ke apa yang Anda inginkan. Untuk mengubah ketinggian aktual dengan CSS ke otomatis saat ini tidak mungkin, tetapi mentransformasikan konten di dalamnya adalah, karenanya transisi ukuran font.

  • Catatan - ada IS javascript di codepen, tetapi hanya tujuannya adalah untuk menambah / menghapus kelas css pada klik untuk akordeon. Ini bisa dilakukan dengan tombol radio tersembunyi, tetapi saya tidak fokus pada hal itu, hanya transformasi ketinggian.
Mike S.
sumber
1
Secara efektif menggandakan jawaban ini , tetapi menghilangkan efek opacity-pudar.
SeldomNeedy
Sepakat. Pendekatan yang lebih baik.
Mike S.