2026.07.01
最終更新:2026.08.01
【GSAP】アニメーションさせた要素にmix-blend-modeが効かなくなる問題の原因と対処法

mix-blend-modeは、ある要素同士を視覚的にブレンドするために用いられます。
しかし、GSAPでアニメーションを実装した際、意図せずmix-blend-modeが機能しなくなるケースがあります。
本記事ではその原因と、考えられるブラウザの描画仕様、ならびに現実的な回避方法について整理します。
mix-blend-modeが効かなくなる原因は?
GSAPはアニメーション処理を最適化するため、内部でtransform: translate3d()を多用します。
そしてtranslate3d()が要素に付与されると、その要素は新しいスタッキングコンテキストを形成します。
ですが、mix-blend-modeは同じスタッキングコンテキスト内にある背景とのブレンドを前提とするプロパティです。
要素が別のスタッキングコンテキストに分離されると背景を参照できなくなり、ブレンドが成立しません。
つまりmix-blend-modeが効かなくなるのは、GSAPが意図せず多用するtransform: translate3d()によって、要素と背景が別のスタッキングコンテキストに置かれてしまうことが原因です。
※補足:スタッキングコンテキスト(描画コンテキスト)とは
- 要素の「描画順」を管理するための概念
transform: translate3D(),z-index,will-changeなどによって新たに生成される- 「レイヤー」と読み替えてもよいかも
- 新しい描画レイヤーが作られると「別の紙に描かれている状態」になるイメージ
問題が起こるケース
1.セレクタの対象が広すぎるケース
初歩的ですが、最初に確認すべきポイントは、他の場所で書かれているGSAPのセレクタが影響していないかどうかです。
たとえば以下のように子要素すべてを対象にする指定を行うと、本来動かす必要のなかった要素にもtranslate3D()が付与され、結果としてmix-blend-modeが期待通りに働かなくなることがあります。
tl.to(".title", { x: 100 });
※GSAPの場合、2次元方向(x, y)への移動しかしない場合でもtranslate3D()が使用されるため、新しいスタッキングコンテキストが生成されてしまいます。
セレクタの範囲を限定することで、余計なtranslate3D()の付与を避けられます。
tl.to(".section-a .title", { x: 100 });
まずはブラウザの検証ツールを使用して、該当要素にtransform: translate3D()が付与されていないか確認するのがオススメです。(初歩的だけどめっちゃ大事)
2.意図せずtranslate3D()が付与されてしまうケース
次に、一見translate3D()を使用しなさそうなアニメーションを指定した場合でも、意図せずtranslate3D()が付与されてしまうケースです。
例えば下記のようにopacityのみ指定した場合でも、描画の最適化(ハードウェアアクセラレーション)のためにtranslate3D()が付与されることがあります。
tl.to(".target", { opacity: 1 });
このような場合、以下のようにforce3D: falseを付けるのがオススメです。ハードウェアアクセラレーションのためのtranslate3D()が使用されにくくなります。
tl.to(".target", {
opacity: 1,
force3D: false
});
それでも解決しない場合は、CSSのみでトランジションやアニメーションを実現できないか検討しましょう。(コードが分散してしまうのがネックですが仕方ないですね……)
3.後からmix-blend-modeを付与しようとしたケース
次は、一度GSAPでアニメーションした後、別タイミングでmix-blend-modeを適用するケースです。
以下のようなシチュエーションが考えられます。
- 要素をアニメーションで出現させた後、ホバーやクリックの際に一瞬だけ
mix-blend-modeを適用させたい - 要素をアニメーションで出現させた後、スクロール中の一部区間でのみ
mix-blend-modeを適用させたい
しかし、出現時のアニメーションによって付与されたtransform: translate3D()が残ったままだと、その後mix-blend-modeを付与しても効果が反映されません。
この場合、アニメーション終了後にGSAPのclearPropsを使ってtransformを削除するのが有効です。
const tl = gsap.timeline();
tl.from(".target", { opacity: 0, x: -50 });
tl.to(".target", { opacity: 1 });
// transformを明示的に消しておく
tl.set(".target", { clearProps: "transform" });
// clearProps: "all" としても問題ないが
// GSAPで付与したプロパティがすべて消えるのでレイアウト崩れに注意
tl.set(".target", { clearProps: "all" });
// clearProps実施後、blend を前提とした別の演出へ
tl.to(".target", { mixBlendMode: "screen" });
※transform: none;では解決せず、clearPropsで明示的にプロパティをクリアする必要があるため注意です。
transformとmix-blend-modeを共存させるには?
今までの説明を踏まえると、transformとmix-blend-modeは共存できないように思えますが、ブレンドさせたい要素と背景を同じスタッキングコンテキストにまとめ、親要素を動かすようにすることで解決する場合があります。
HTML例:
<div class="transform-target"> <div class="background"></div> <div class="blend-target"></div> </div>
CSS例:
.transform-target {
position: relative;
}
.background {
position: absolute;
inset: 0; // 位置やサイズは任意でOK
background: linear-gradient(135deg, #ff8a00, #3a00ff);
z-index: 0;
}
.blend-target {
position: absolute;
inset: 0; // 位置やサイズは任意でOK
z-index: 1;
mix-blend-mode: difference;
}
GSAP例:
gsap.to(".transform-target", {
x: 120,
y: -20,
rotate: 15,
duration: 1.2,
ease: "power3.out",
});
ただしこの方法の注意点として、親要素の外にある背景とブレンドさせる表現ができなくなってしまうという制約があります。
その回避策として、背景 & ブレンドさせたい要素 & 動かしたい要素、3つの要素の構造を以下のように見直すと改善できる場合があります。
HTML例:
<div class="section">
<div class="blend-target">
<div class="transform-target"></div>
</div>
<div class="background"></div>
</div>
CSS例:
.blend-target {
position: relative;
mix-blend-mode: difference;
}
.transform-target {
position: relative;
z-index: 1;
}
.background {
position: absolute;
inset: 0;
background: linear-gradient(135deg, #ff8a00, #3a00ff);
z-index: 0;
}
GSAP例:
gsap.to(".transform-target", {
x: 120,
y: -20,
rotate: 15,
duration: 1.2,
ease: "power3.out",
});
実現したいレイアウトやアニメーションによって最適解が変わるため、スタッキングコンテキストの概念を踏まえつつ、構造を工夫してみてください。
※コードが分散してしまいますが、CSSでXY方向のtransform: translate()を使用する方法でも回避できる可能性アリです。
おわりに
mix-blend-modeは簡単に書ける反面、ブラウザ内の描画処理に深く関わる性質を持っています。そのため、アニメーションとの併用は思わぬ挙動を引き起こしがちです。
本記事が、同じ問題で困っている方のヒントとなれば嬉しいです。
参考になったよ~~という方は、下のボタンからぜひシェアをお願いします!
Writerこの記事をかいたひと
Related Topics関連記事




