div - css transition width



我怎樣才能過渡高度:0; 高度:自動; 用CSS? (20)

Flexbox解決方案

優點:

  • 簡單
  • 沒有JS
  • 平穩過渡

缺點:

  • 元素需要放在固定高度的flex容器中

它的工作方式是始終使用flex-basis:對包含內容的元素執行auto,然後轉換flex-grow和flex-shrink。

編輯:改進的JS小提琴靈感來自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小提琴

我試圖使用CSS過渡使<ul>向下滑動。

<ul>height: 0;開始height: 0; 。 懸停時,高度設置為height:auto; 。 然而,這導致它只是出現而不是過渡,

如果我從height: 40px;height: 40px; height: auto; ,然後它會滑到height: 0; ,然後突然跳到正確的高度。

如果不使用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>


Answer #1

我想我想出了一個非常可靠的解決方案

好!我知道這個問題與互聯網一樣古老,但我認為我有一個解決方案,我變成了一個名為突變轉換插件style=""每當DOM發生變化時,我的解決方案都會為跟踪元素設置屬性。最終結果是你可以使用好的ole CSS進行轉換,而不是使用hacky修復程序或特殊的javascript。您唯一需要做的就是使用相關元素設置要跟踪的內容data-mutant-attributes="X"

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

而已!此解決方案使用MutationObserver來跟踪DOM中的更改。因此,您不需要設置任何內容或使用javascript手動設置動畫。自動跟踪更改。但是,因為它使用MutationObserver,所以這只會在IE11 +中進行轉換。

小提琴!


Answer #2

使用CSS3過渡動畫高度的可視化解決方法是為填充設置動畫。

你沒有完全獲得完全擦除效果,但是使用transition-duration和padding值可以讓你足夠接近。 如果您不想明確設置height / max-height,那麼這應該是您正在尋找的。

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/ (在jsFiddle之上翻過stephband)


Answer #3

傑克對最大高度動畫的答案很棒,但我發現設置一個大的最大高度令人煩惱的延遲。

可以將可折疊內容移動到內部div中,並通過獲取內部div的高度來計算最大高度(通過JQuery,它將是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');
});

這是一個jsfiddle鏈接:http://jsfiddle.net/pbatey/duZpThttp://jsfiddle.net/pbatey/duZpT

這是一個jsfiddle,需要絕對最少的代碼:http://jsfiddle.net/8ncjjxh8/http://jsfiddle.net/8ncjjxh8/


Answer #4

將高度設置為自動並轉換最大高度。

在Chrome v17上測試過

div {
  position: absolute;
  width:100%;
  bottom:0px;
  left:0px;

  background:#333;
  color: #FFF;

  max-height:100%; /**/
  height:auto; /**/

  -webkit-transition: all 0.2s ease-in-out;
  -moz-transition: all 0.2s ease-in-out;
  -o-transition: all 0.2s ease-in-out;
  -ms-transition: all 0.2s ease-in-out;
  transition: all 0.2s ease-in-out;
}

.close {
  max-height:0%; /**/
}

Answer #5

您可以從height:0過渡到height:auto,同時提供最小高度和最大高度。

div.stretchy{
    transition: 1s linear;
}

div.stretchy.hidden{
    height: 0;
}

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

Answer #6

我一直使用的解決方案是先淡出,然後縮小font-sizepaddingmargin值。 它與擦拭看起來不一樣,但它沒有靜態heightmax-height

工作範例:

/* final display */
#menu #list {
    margin: .5em 1em;
    padding: 1em;
}

/* hide */
#menu:not(:hover) #list {
    font-size: 0;
    margin: 0;
    opacity: 0;
    padding: 0;
    /* fade out, then shrink */
    transition: opacity .25s,
                font-size .5s .25s,
                margin .5s .25s,
                padding .5s .25s;
}

/* reveal */
#menu:hover #list {
    /* unshrink, then fade in */
    transition: font-size .25s,
                margin .25s,
                padding .25s,
                opacity .5s .25s;
}
<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>


Answer #7

我意識到這個帖子已經老了,但它在某些谷歌搜索中排名很高,所以我認為它值得更新。

您還可以獲取/設置元素自己的高度:

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

您應該在內聯腳本標記中的target_box的結束標記之後立即轉儲此Javascript。


Answer #8

我的解決方法是將max-height轉換為精確的內容高度以獲得漂亮的平滑動畫,然後使用transitionEnd回調將max-height設置為9999px,以便內容可以自由調整大小。

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>


Answer #9

我知道這是這個問題的三十分之一的答案,但我認為這是值得的,所以這裡有。 這是一個僅支持CSS的解決方案,具有以下屬性:

  • 一開始沒有延遲,過渡不會提前停止。 在兩個方向(展開和折疊)中,如果在CSS中指定300毫秒的轉換持續時間,則轉換需要300毫秒(週期)。
  • 它正在轉換實際高度(與transform: scaleY(0) ),因此如果在可折疊元素之後有內容,它會做正確的事情。
  • 雖然(和其他解決方案一樣)有魔術數字(比如“選擇一個比你的盒子更高的長度”),如果你的假設最終錯了,那就不是致命的。 在這種情況下,轉換可能看起來並不驚人,但在轉換之前和之後,這不是問題:在擴展( height: auto )狀態下,整個內容始終具有正確的高度(例如,如果您選擇max-height結果太高了。 在崩潰的狀態下,高度應該是零。

演示

這是一個包含三個可折疊元素的演示,所有元素都具有不同的高度,所有元素都使用相同的CSS。 單擊“運行代碼段”後,您可能需要單擊“完整頁面”。 請注意,JavaScript僅切換collapsed CSS類,不涉及測量。 (你可以使用複選框或:target沒有任何JavaScript的精確演示)。 另請注意,負責轉換的CSS部分非常短,而HTML只需要一個額外的包裝元素。

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

它是如何工作的?

實際上有兩個轉變涉及實現這一點。 其中一個將margin-bottom從0px(處於展開狀態) -2000px為折疊狀態下的-2000px (類似於此答案 )。 這裡的2000是第一個神奇的數字,它基於你的盒子不會高於此的假設(2000像素似乎是一個合理的選擇)。

單獨使用margin-bottom過渡本身有兩個問題:

  • 如果你實際上有一個高於2000像素的盒子,那麼margin-bottom: -2000px將不會隱藏所有內容 - 即使在折疊的情況下也會有可見的東西。 這是一個小修復,我們稍後會做。
  • 如果實際的盒子是1000像素高,並且你的過渡是300ms長,那麼可見的過渡在大約150ms之後已經結束(或者,相反的方向,開始晚150ms)。

修復第二個問題是第二個轉換的位置,這個轉換在概念上針對包裝器的最小高度(“概念上”,因為我們實際上並沒有使用min-height屬性;稍後將詳細介紹)。

這是一個動畫,顯示瞭如何將底部邊緣過渡與最小高度過渡相結合,兩者俱有相同的持續時間,為我們提供了從全高度到零高度的組合過渡,具有相同的持續時間。

左側欄顯示負底部邊緣如何向下推動底部,降低可見高度。 中間欄顯示最小高度如何確保在折疊情況下,過渡不會提前結束,並且在擴展的情況下,過渡不會延遲。 右側欄顯示兩者的組合如何使盒子在正確的時間內從全高度過渡到零高度。

對於我的演示,我已經確定50px作為最小高度值的上限。 這是第二個神奇的數字,它應該低於盒子的高度。 50px似乎也是合理的; 你似乎不太可能經常想要製作一個折疊的元素,它首先不是50像素高。

正如您在動畫中看到的那樣,所產生的過渡是連續的,但它是不可微分的 - 當最小高度等於由下邊距調整的全高時,速度會突然改變。 這在動畫中非常明顯,因為它對兩個過渡使用線性定時功能,並且因為整個過渡非常慢。 在實際情況下(我的演示在頂部),轉換只需要300毫秒,底部邊距轉換不是線性的。 我已經為這兩種轉換玩了很多不同的計時功能,而我最終感覺它們最適合各種各樣的情況。

還有兩個問題需要解決:

  1. 從上面開始,在折疊狀態下,超過2000像素高度的盒子沒有被完全隱藏,
  2. 和相反的問題,在非隱藏的情況下,即使轉換未運行,高度小於50像素的框也太高,因為最小高度使它們保持在50像素。

我們通過在折疊的情況下給容器元素一個max-height: 0解決第一個問題,轉換為0s 0.3s 。 這意味著它不是真正的過渡,但max-height應用了延遲; 它只適用於轉換結束後。 為了使其正常工作,我們還需要為相反的非折疊狀態選擇數字max-height 。 但與2000px的情況不同,選擇太大的數字會影響轉換的質量,在這種情況下,它確實無關緊要。 所以我們可以選擇一個如此之高的數字,以便我們知道沒有任何高度可以接近這一點。 我選了一百萬像素。 如果您覺得可能需要支持高度超過一百萬像素的內容,那麼1)我很抱歉,2)只需添加幾個零。

第二個問題是我們實際上沒有使用min-height進行最小高度轉換的原因。 相反,容器中有一個::after偽元素,其height從50px過渡到零。 這與min-height具有相同的效果:它不會讓容器收縮到偽元素當前所具有的任何高度以下。 但是因為我們使用的是height ,而不是min-height ,我們現在可以使用max-height (再次應用延遲)將轉換結束時偽元素的實際高度設置為零,確保至少在過渡,即使是小元素也有正確的高度。 因為min-heightmax-height min-height stronger ,所以如果我們使用容器的min-height而不是偽元素的height ,這將不起作用。 就像前一段中的max-height一樣,這個max-height也需要一個轉換另一端的值。 但在這種情況下,我們可以選擇50px。

測試過Chrome(Win,Mac,Android,iOS),Firefox(Win,Mac,Android),Edge,IE11(除了我的演示中的flexbox佈局問題,我沒有打擾調試)和Safari(Mac,iOS) )。 說到flexbox,應該可以在不使用任何flexbox的情況下完成這項工作; 事實上,我認為你幾乎可以使所有東西都在IE7中工作 - 除了你不會有CSS過渡這一事實,這使得它成為一個毫無意義的練習。


Answer #10

沒有硬編碼值。

沒有JavaScript。

沒有近似值。

訣竅是使用隱藏和重複div,讓瀏覽器了解100%的含義。

只要您能夠複製要設置動畫的元素的DOM,此方法就適用。

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


Answer #11

當其中一個高度為auto ,您無法在高度上設置動畫,您必須設置兩個明確的高度。


Answer #12

max-height對每個州使用不同的轉換緩和和延遲。

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

參見示例:http://jsfiddle.net/0hnjehjc/1/http://jsfiddle.net/0hnjehjc/1/


Answer #13

好的,所以我想我想出了一個超級簡單的答案......不max-height,使用relative定位,在li元素上工作,並且是純CSS。除了Firefox之外,我還沒有測試過任何東西,儘管從CSS來看,它應該適用於所有瀏覽器。

FIDDLE:http://jsfiddle.net/n5XfG/2596/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>

Answer #14

幾乎沒有提到在Element.scrollHeight這裡有用的屬性,仍然可以用於純CSS過渡。該屬性始終包含元素的“完整”高度,無論其內容是否以及如何因折疊高度而溢出(例如height: 0)。

因此,對於height: 0(有效完全折疊的)元素,其“正常”或“完整”高度仍然可通過其scrollHeight值(總是像素長度)容易地獲得。

對於這樣的元素,假設它已經具有類似的轉換設置(使用ul原始問題):

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

我們可以使用CSS來觸發所需的動畫“高度擴展”,使用類似下面的內容(這裡假設ul變量引用列表):

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

而已。如果您需要折疊列表,則以下兩個語句中的任何一個都將執行:

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

我的特定用例圍繞著未知且通常相當長的動畫列表,因此我不習慣定制任意“足夠大” heightmax-height規範,並冒著截斷內容或內容突然需要滾動的內容(overflow: auto例如,如果) 。此外,寬鬆和時間與破max-height基於解決方案,因為所使用的高度可達到最大值很多早於它會採取max-height到達9999px。隨著屏幕分辨率的增長,像素長度就像9999px在我嘴裡留下了不好的味道。在我看來,這個特殊的解決方案以優雅的方式解決了這個問題。

最後,這里希望CSS的未來版本能夠更好地解決作者需要更好地完成這些事情 - 重新審視“計算”與“已使用”和“已解決”值的概念,並考慮轉換是否應適用於計算值,包括與width和的轉換height(目前得到一些特殊處理)。


Answer #15

我最近一直在轉變max-heightli元素,而不是包裝ul

其理由是,對於小的延遲max-heights遠沒有那麼明顯(如果有的話)相比大max-heights了,我也可以把我的max-height相對值font-sizeli使用,而不是一些任意數量巨大ems或者rems

如果我的字體大小是1rem,我會將我設置max-height為類似3rem(以容納包裝文本)。你可以在這裡看到一個例子:

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


Answer #16

接受的答案適用於大多數情況,但是當你的div高度變化很大時它不能很好地運行 - 動畫速度不依賴於內容的實際高度,並且它看起來不穩定。

您仍然可以使用CSS執行實際動畫,但是您需要使用JavaScript來計算項目的高度,而不是嘗試使用auto。不需要jQuery,但如果你想要兼容性,你可能需要稍微修改一下(在最新版本的Chrome中工作:))。

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>


Answer #17

正如我發布的那樣,已有超過30個答案,但我覺得我的答案在傑克已經接受的答案上有所改進。

我不滿足於簡單地使用max-height和CSS3過渡所引起的問題,因為許多評論者指出,你必須將你的max-height值設置得非常接近實際高度,否則你會得到一個延遲。有關該問題的示例,請參閱此JSFiddle

為了解決這個問題(雖然仍然沒有使用JavaScript),我添加了另一個轉換transform: translateYCSS值的HTML元素。

這意味著使用max-heighttranslateY使用:max-height允許元素按下它下面的元素,同時translateY給出我們想要的“即時”效果。問題max-height仍然存在,但其影響有所減輕。這意味著您可以為您的max-height價值設置更大的高度,並減少對它的擔憂。

總體好處是,在轉換回(崩潰)時,用戶會translateY立即看到動畫,因此max-height花費多長時間並不重要。

解決方案如小提琴

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>


Answer #18

這不是問題的“解決方案”,而是更多的解決方法。它只能用文本編寫,但可以根據需要更改為與其他元素一起使用我敢肯定。

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

這是一個例子:http://codepen.io/overthemike/pen/wzjRKahttp://codepen.io/overthemike/pen/wzjRKa

基本上,您將font-size設置為0並以足夠快的速度轉換而不是height,max-height或scaleY()等,以獲得轉換為您想要的高度。目前無法將CSS的實際高度轉換為自動,但轉換內容是因為字體大小的轉換。

  • 注意 - 在codepen中有javascript,但它的唯一目的是在手風琴點擊時添加/刪除css類。這可以通過隱藏的單選按鈕完成,但我沒有專注於那個,只是高度轉換。

Answer #19

這是一種從任何起始高度(包括0)過渡到自動(完整大小和靈活)的方法,無需基於每個節點的硬件代碼或任何初始化的用戶代碼:https://github.com/csuwildcat/transition-autohttps://github.com/csuwildcat/transition-auto。這基本上是你想要的聖杯,我相信 - > http://codepen.io/csuwldcat/pen/kwsdF。只需將以下JS文件打入您的頁面,之後您需要做的就是添加/刪除一個布爾屬性reveal=""- 來自您要擴展和收縮的節點。

一旦您包含示例代碼下方的代碼塊,您就需要以用戶身份完成所有操作:

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

這是包含在您頁面中的代碼塊,之後,它都是肉汁:

將這個JS文件放在你的頁面中 - 這一切都是Just Works™

/ *高度代碼:auto; 過渡* /

(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代碼* /

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




css-transitions