1. ホーム
  2. ジャバスクリプト

[解決済み】CSSのトランジション効果を一時的に無効にする一番きれいな方法は何ですか?

2022-04-04 11:31:31

質問

以下のような効果が適用されたDOM要素を持っています。

#elem {
  -webkit-transition: height 0.4s ease;
  -moz-transition: height 0.4s ease;
  -o-transition: height 0.4s ease;
  transition: height 0.4s ease;
}

私はこの要素のサイズを変更するjQueryプラグインを書いています。私はスムーズにサイズを変更できるように、これらの効果を一時的に無効にする必要があります。

これらの効果を一時的に無効にする(そして再び有効にする)最もエレガントな方法は何でしょうか。

解決方法は?

簡単な答え

このCSSを使用してください。

.notransition {
  -webkit-transition: none !important;
  -moz-transition: none !important;
  -o-transition: none !important;
  transition: none !important;
}

さらに、このJS(jQueryなし)のどちらかを...

someElement.classList.add('notransition'); // Disable transitions
doWhateverCssChangesYouWant(someElement);
someElement.offsetHeight; // Trigger a reflow, flushing the CSS changes
someElement.classList.remove('notransition'); // Re-enable transitions

あるいは、このJSをjQueryで...

$someElement.addClass('notransition'); // Disable transitions
doWhateverCssChangesYouWant($someElement);
$someElement[0].offsetHeight; // Trigger a reflow, flushing the CSS changes
$someElement.removeClass('notransition'); // Re-enable transitions

... あるいは、あなたが使っている他のライブラリやフレームワークを使って同等のコードを書いてください。

説明

これは、実はかなり微妙な問題なのです。

まず最初に、'notransition' クラスを作成して、要素に適用し、その *-transition CSS属性に none . 例えば

.notransition {
  -webkit-transition: none !important;
  -moz-transition: none !important;
  -o-transition: none !important;
  transition: none !important;
}

<サブ (余談ですが、この記事では -ms-transition が入っています。必要ないでしょ。Internet Explorerの最初のバージョンでは、遷移をサポートするために まったく はIE10で、接頭辞なしでサポートされました)。

しかし、これは単なるスタイルであり、簡単なことです。このクラスを使おうとすると、ある罠にぶつかる。その罠とは、このようなコードは、あなたが素朴に期待するようには動かないということです。

// Don't do things this way! It doesn't work!
someElement.classList.add('notransition')
someElement.style.height = '50px' // just an example; could be any CSS change
someElement.classList.remove('notransition')

素直に考えれば、高さの変化は「notransition」クラスが適用されている間に起こるので、アニメーションにはならないだろうと思うかもしれません。しかし、実際には する 少なくとも私が試したすべてのモダンブラウザで、アニメーションが表示されました。問題は、ブラウザがJavaScriptの実行が終わるまで、必要なスタイルの変更をキャッシュし、一度のリフローですべての変更を行うことです。その結果、トランジションが有効かどうかに正味の変化はないものの、高さには正味の変化がある状態でリフローが行われます。その結果、高さの変化をアニメーションで表現しています。

これを回避する合理的でクリーンな方法は、'notransition' クラスの削除を、次のように 1ms のタイムアウトでラップすることだと思うかもしれません。

// Don't do things this way! It STILL doesn't work!
someElement.classList.add('notransition')
someElement.style.height = '50px' // just an example; could be any CSS change
setTimeout(function () {someElement.classList.remove('notransition')}, 1);

が、これも確実に動作するわけではありません。WebKit ブラウザでは上記のコードが壊れることはありませんでしたが、Firefox では(遅いマシンでも速いマシンでも)時々(一見ランダムに)素朴なアプローチを使ったときと同じ動作になることがあります。この理由は、JavaScript の実行が十分に遅く、ブラウザがアイドル状態になり、そうでなければ日和見的なリフローを行おうと考えている時点でタイムアウト関数の実行を待っている可能性があり、そのシナリオが発生すると Firefox はリフローの前にキューに入った関数を実行するからだと思われます。

この問題を解決するために、私が見つけた唯一の方法は を削除する前に、その要素に加えられたCSSの変更をフラッシュし、要素のリフローを行います。これを行うには、さまざまな方法があります。 ここで があります。標準的な方法として一番近いのは offsetHeight プロパティを使用します。

では、実際に機能する1つの解決策はというと

someElement.classList.add('notransition'); // Disable transitions
doWhateverCssChangesYouWant(someElement);
someElement.offsetHeight; // Trigger a reflow, flushing the CSS changes
someElement.classList.remove('notransition'); // Re-enable transitions

ここで説明した3つの可能なアプローチ(成功した1つのアプローチと失敗した2つのアプローチの両方)を説明するJSフィドルを紹介します。 http://jsfiddle.net/2uVAA/131/