幅と高さが自動である要素をアニメーション化する方法(折りたたみパネル)

css属性がautoである要素はアニメーション化できず、アニメーションは次のコードのように効果がありません。

.dropdown {
    
    
  transition: 0.2s;
  height: 0;
}
.dropdown.open {
    
    
  /* 高度发生了改变,但是没有动画. */
  height: auto;
}

誰もが折りたたみパネルについて知っているように、要素はCSSトランジションを使用してスムーズに折りたたみ、展開できることが望まれますが、その展開サイズは内部のコンテンツに依存します。

トランジションが設定されていますtransition: 0.2sが、拡張アニメーションは有効になりません。この問題は、高度がautoによって自動的に計算される場合にのみ発生することがわかりました。パーセンテージ、ピクセル値、絶対単位はすべて正常に機能します。ただし、これらはすべて、要素コンテンツのサイズによって自然に決定されるのではなく、事前に特定の高さを設定する必要があります。

ブラウザーがこの問題を解決しないのはなぜですか?

Mozilla開発者のドキュメントによると、auto値はCSS遷移アニメーションプロパティの仕様から意図的に除外されています。サポートされている属性を確認するには、このドキュメントを参照してください:ポータル完全なコンテンツはこちらMDN:リンク

すべての要素のサイズと位置を再計算することは、ブラウザで非常にパフォーマンスを消費します。要素をautoの高さに遷移させる場合、ブラウザはアニメーションの各ステージでリフローを実行して、他のすべての要素がどのように移動するかを決定する必要があります。単純な方法でキャッシュまたは計算することはできません。これは、展開されたときに、どれくらいの高さに展開できるかがわからないためです。これは、ブラウザがバックグラウンドで実行する必要がある数学的計算を複雑にし、パフォーマンスを明らかな方法で低下させる可能性があります。

この問題を解決するには?参考のために、実装のアイデアをいくつか示します。

最大高さ

前述のように、CSS値は固定単位値間でのみ変換できます。しかし、高さがautoに設定されている要素があり、その最大の高さが1000pxなどの固定値に設定されているとします。高さは変換できませんが、明示的な値があるため、最大の高さは変換できます。いつでも、要素の実際の高さは、高さの最大値と最大高さによって決まります。したがって、最大の高さの値がautoの値より大きい限り、最大の高さを変換して目的の効果を得ることができます。

これには2つの重要な欠点があります。1.高さを事前に予測する必要があります。2.均一なアニメーションを使用することをお勧めします。

変換:scaleY()

実装は次のようになります。要素の変換属性の変換を設定し、transform:scaleY(1)とtransform:scaleY(0)を切り替えます。これは、「最初と同じスケールで要素を表示する(y軸上)」と「0のスケールで要素を表示する(y軸上)」ことをそれぞれ意味します。これらの2つの状態間の遷移は、要素の自然なサイズとコンテンツベースのサイズを巧みに「絞り込み」ます。欠点は何ですか?リフローはトリガーされないため、この要素を囲む要素はまったく影響を受けません。つまり、要素が展開されても、次の要素は下に移動しません。

このソリューションは、要素の配置に使用するのに適しています。たとえば、element-uiの選択コンポーネントは、このソリューションに基づくドロップダウン拡張です。

JavaScript

最後はJSの実装で、効果も最高ですが、コードの実装には一定の困難があります。

折りたたみ部分をスムーズに移行する必要がある場合、展開サイズはコンテンツによって完全に決定され、ページの他の要素は移行中に自動的に拡大および縮小します。JavaScriptを使用してこれを実現できます。

<div class="container">
  <div class="section">
    <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</p>
  </div>
  <div class="section collapsible">
    <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
  </div>
  <div class="section">
   <p>Ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</p>
  </div>
</div>

<button id="toggle-button">Toggle collapse</button>

JS

function collapseSection(element) {
  var sectionHeight = element.scrollHeight;
  
  var elementTransition = element.style.transition;
  element.style.transition = '';
  
  requestAnimationFrame(function() {
    element.style.height = sectionHeight + 'px';
    element.style.transition = elementTransition;
    
    requestAnimationFrame(function() {
      element.style.height = 0 + 'px';
    });
  });
  
  element.setAttribute('data-collapsed', 'true');
}

function expandSection(element) {
  var sectionHeight = element.scrollHeight;
  element.style.height = sectionHeight + 'px';

  element.addEventListener('transitionend', function(e) {
    element.removeEventListener('transitionend', arguments.callee);
    element.style.height = null;
  });
  
  element.setAttribute('data-collapsed', 'false');
}

document.querySelector('#toggle-button').addEventListener('click', function(e) {
  var section = document.querySelector('.section.collapsible');
  var isCollapsed = section.getAttribute('data-collapsed') === 'true';
    
  if(isCollapsed) {
    expandSection(section)
    section.setAttribute('data-collapsed', 'false')
  } else {
    collapseSection(section)
  }
});

最後に、Vueを使用して開発している場合は、折りたたみパネルコンポーネントを作成する必要があります。この記事を参照してください:リンクの説明を追加する

おすすめ

転載: blog.csdn.net/wu_xianqiang/article/details/107055672