• CSSのwill-changeは変化するpropertyを必要な要素へ短時間だけ指定する

CSSのwill-changeは変化するpropertyを必要な要素へ短時間だけ指定する

公開日: 執筆:佐藤

will-changeは、近いうちに変化させるpropertyをuser agentへ事前に知らせるrendering hintです。transformを動かす要素ならwill-change: transformと指定し、animationが終わったら初期値のautoへ戻します。

すべての要素へ常時指定するperformance設定ではありません。対象要素、変化するproperty、使う期間を絞ります。user agentがどの最適化を行うかは保証されないため、指定の有無を対象browserで比べて判断してください。

will-changeは変化そのものではなく事前のhintである

CSSのwill-changeは、要素に起こる変化を前もってuser agentへ伝えます。animationが始まる前に、描画に必要な準備を行えるようにするpropertyです。

.panel {
  will-change: transform;
}

この指定は、.panelを移動させません。移動、回転、拡大の内容はtransformへ書きます。will-changeは、そのpropertyが近いうちに変わるというhintだけを渡します。

will-change: transformを指定しても、要素が必ず独立したGPU layerになるとは限りません。browserごとに使い方は異なり、同じbrowserでも利用できる資源や指定数によって最適化を変えられます。

auto、scroll-position、contents、property名を使い分ける

will-changeの初期値はautoで、すべての要素に適用でき、継承されません。指定できる値は次のように分かれます。

値 事前に知らせる変化
auto 特定の変化を知らせず、通常の判断をuser agentへ任せる
scroll-position 要素のscroll位置が近いうちに変わる
contents 要素の内容が近いうちに変わる
transformやopacityなどのproperty名 そのpropertyが近いうちに変わる

複数の変化を知らせる場合は、commaで区切ります。

.dialog {
  will-change: transform, opacity;
}

指定したpropertyごとに特別な最適化が行われるとは限りません。user agentが特別な準備を持たないpropertyでは、指定しても効果がない場合があります。候補を増やすのではなく、実際に変えるpropertyだけを書きます。

変化の少し前に指定し終了後はautoへ戻す

will-changeは、変化する要素へ必要な時間だけ使います。次は処理の役割を示す説明用の仮例です。

function prepareTransform(element) {
  element.style.willChange = 'transform';
}

function finishTransform(element) {
  element.style.willChange = 'auto';
}

prepareTransform()は、要素を動かす少し前の操作で呼びます。finishTransform()は、transitionまたはanimationが終わった後に呼びます。実際のeventは、開閉button、slide切替、drag開始など、その部品が持つ操作に合わせて決めます。

変化と同時に指定すると、user agentが準備する時間を取れません。反対に、pageを開いてから閉じるまで付け続けると、もう変化しない要素にも準備状態を残します。「動かす可能性がある」だけではなく、「まもなく動かす」と判断できる時点で指定してください。

大量指定はmemoryと描画の負担を増やし得る

要素を独立したlayerとして扱う最適化には、準備時間だけでなくmemoryも必要です。大量の要素へwill-changeを指定すると、user agentはGPU memoryの消費を避けるため、hintを使わない場合があります。

次のような常時指定は避けます。

* {
  will-change: transform, opacity;
}

これは、変化しない要素まで対象にし、何を最適化すべきかという情報を薄めます。部品名で対象を一つに絞り、指定前後でanimation開始時の引っ掛かり、scroll、memory消費、ほかの要素の描画を確認します。

will-changeで表示が速くなると決め付けず、問題が見える箇所へだけ試します。問題の原因が大きな画像、複雑なJavaScript、頻繁なlayout計算なら、hintを加える前に原因となる処理を減らす方が先です。

stacking contextが先に作られる場合がある

あるpropertyの初期値以外がstacking contextを作る場合、そのpropertyをwill-changeへ指定した時点でもstacking contextが作られます。たとえばopacityは、1以外の値でstacking contextを作ります。そのため、opacityがまだ1でも、will-change: opacityによって重なり方が変わる場合があります。

.notice {
  opacity: 1;
  will-change: opacity;
}

animationの滑らかさだけを確認し、前後の要素との重なりを見ないと、z-indexの効く範囲が変わったことを見落とします。指定する要素の親子関係とstacking contextを確認し、重なりが変わるなら構造を見直します。

CSS Will Change Module Level 1はFirst Public Working Draftです。対象browserがpropertyと値を解釈するか、どの最適化を行うかは実装で確かめる必要があります。未対応browserでは宣言が無視されても部品が動くように、animation自体をwill-changeへ依存させないでください。

最初の一手は、開始時に引っ掛かる一つの要素を選び、実際に変えるpropertyを一つだけ指定することです。変化の少し前に加え、終了後にautoへ戻し、指定しない場合と同じ操作で比べます。

戻る