ついにCSSだけでwidth: auto;やheight: auto;へのアニメーションができるようになります
Post on:2024年10月31日
CSSだけでwidth: auto;
やheight: auto;
にアニメーションできたらいいな、と思ったことはありませんか?
たとえば、下記のようにテキストの量によってサイズが異なるボタンです。
これまではCSSでアニメーションするときは、固定値(width: 100px;
しかアニメーションが機能しませんでしたが、Chrome 129でサポートされたinterpolate-size
プロパティやcalc-size()
関数を使用すると、簡単にwidth: auto;
へのアニメーションが実装できます。
Animate to height: auto; in CSS
by Bramus!
下記は各ポイントを意訳したものです。
※元サイト様のライセンスに基づいて翻訳しています。基づいてというのは、貢献部分に関して同ライセンスも含みます。
はじめに
CSS Dayのカンファレンスで参加者からリクエストが多かったCSSの機能の一つが、height: auto;
のアニメーション機能です。もちろん、バリエーションとしてwidth: auto;
のアニメーション、そしてmin-content
, max-content
, fit-content
などのキーワードで表される固有サイズのどれかにアニメーションさせることも挙げられます。
どういうことかというと、たとえば下記のデモで、アイコンをホバーしたときにラベルがスムーズに自然な幅(auto
)にアニメーションできるようになると嬉しいというものです。
これまでだと、下記のデモのようにアニメーションが機能しません。
See the Pen
Growing buttons on hover (before) by coliss (@coliss)
on CodePen.
上記のデモのCSSには、下記のようにアニメーションするように記述されています。
1 2 3 4 5 6 7 8 9 10 |
nav a { width: 80px; overflow-x: clip; transition: width 0.35s ease; /* 幅をトランジションさせる */ &:hover, &:focus-visible { width: max-content; /* トランジションでは機能しません */ } } |
上記のデモではwidth
プロパティをトランジションさせるようにtransition
を設定し、:hover
でwidth: max-content;
が設定されているにもかかわらず、スムーズなアニメーションは行われません。ホバーすると、急激に設定した幅に変化するだけです。
autoなどのキーワードをアニメーションさせる方法
CSSのinterpolate-size
プロパティを使用すると、CSS固有のサイズ設定キーワードでアニメーションやトランジションを許可するかどうかを設定できます。使い方は簡単で、下記を使用するWebページに追加するだけです。
1 2 3 |
:root { interpolate-size: allow-keywords; } |
上記のデモにこのCSSを追加したデモが下記です。
これでwidth: auto;
へのアニメーション、そしてwidth: auto;
からのアニメーションが正常に動作します。
※2024年10月現在、Chrome 129+のみにサポートされています。
See the Pen
Growing buttons with interpolate-size: allow-keywords by coliss (@coliss)
on CodePen.
interpolate-size
プロパティのデフォルト値はnumeric-only
で、数値のみです。値をallow-keywords
に設定すると、キーワードでアニメーションできるようになります。
interpolate-size
プロパティのサポートブラウザは、下記の通りです。
interpolate-sizeプロパティのサポートブラウザ
Chrome 129でサポートされているキーワードは、auto
, min-content
, max-content
, fit-content
です。将来サポートされる可能性があるキーワードには、stretch
, contain
があります。
セレクタで範囲を制限する
上記ではinterpolate-size
プロパティを:root
にしてドキュメント全体に設定しましたが、一部だけに制限することもできます。たとえば、header
要素がこのようなトランジションに対応していない場合、下記のようにmain
要素とその子孫要素のみに制限できます。
1 2 3 |
main { interpolate-size: allow-keywords; } |
デフォルトでキーワードのアニメーション化を許可しないのはなぜですか?
このメカニズムに関する一般的なフィードバックは、ブラウザはデフォルトで固有サイズのキーワードのトランジションやアニメーションを許可すべきだというものです。
この動作を有効にするオプションは、この機能の開発中に調査されました。ワーキンググループは、多くのスタイルシートが固有サイズのキーワード(auto
など)はアニメーションできないと想定しているため、デフォルトでこれを有効にすることは後方互換性がないことを突き止めました。詳細は、CSS Working Group issueをご覧ください。
したがって、このinterpolate-size
プロパティはオプトインです。継承特性のおかげで、ドキュメント全体をオプトインするには前述のように:root
でinterpolate-size: allow-sizes;
を設定するだけです。
calc-size()でキーワードをアニメーションさせる方法
CSS固有のサイズ設定キーワードでアニメーションさせるもう一つの方法は、calc-size()
関数を使用することです。この関数を使用することで、安全かつ明確に定義された方法で固有のサイズ設定キーワードに対して計算を実行できます。
1 2 3 4 5 6 7 8 9 10 |
nav a { width: 80px; overflow-x: clip; transition: width 0.35s ease; &:hover, &:focus-visible { width: calc-size(max-content, size); /* */ } } |
上記のデモにこのCSSを追加したデモが下記です。
これでwidth: auto;へのアニメーション、そしてwidth: auto;からのアニメーションが正常に動作します。
※2024年10月現在、Chrome 129+のみにサポートされています。
See the Pen
Growing buttons with calc-size() by coliss (@coliss)
on CodePen.
この関数は、次の2つの引数を順番に受け入れます。
- calc-size basis:
<intrinsic-size-keyword>にすることもネストされた calc-size()
にすることもできます。 - calc-size calculation:calc-size basisを用いて計算を実行します。calc-size basisを参照するには
size
キーワードを使用します。
1 2 |
width: calc-size(auto, size); // = the auto width, unaltered width: calc-size(min-content, size); // = the min-content width, unaltered |
calc-size()
のサポートブラウザは、下記の通りです。
視覚的には、interpolate-size
プロパティを使用した場合とまったく同じです。しかし、特定のケースではinterpolate-size
プロパティを使用する必要があります。
calc-size()
が優れているのは計算を実行できることです。これはinterpolate-size
プロパティでは実行できません。
1 2 3 |
width: calc-size(auto, size - 10px); // = autoから10pxを引いた値 width: calc-size(min-content, size + 1rem); // = min-contentから1remを足した値 width: calc-size(max-content, size * .5); // = max-contentの半分の値 |
たとえば、ページ上のすべての段落のサイズを50px
の倍数にもっとも近い値にしたい場合は、次のようにします。
1 2 3 4 |
p { width: calc-size(fit-content, round(up, size, 50px)); height: calc-size(auto, round(up, size, 50px)); } |
実際の動作は、デモページでご覧ください。
See the Pen
grid-size paragraphs thanks to calc-size() by coliss (@coliss)
on CodePen.
calc-size()
関数でできることは、2つのcalc-size()
のcalc-size basisが同じ場合に、それらの間を補間することです。これもinterpolate-size
プロパティでは実現できません。
1 2 3 4 5 6 7 8 |
#element { width: min-content; /* */ transition: width 0.35s ease; &:hover { width: calc-size(min-content, size + 10px); /* */ } } |
どちらを使えばよいのか?
ほとんどの場合、:root
にinterpolate-size
プロパティを使用します。これは基本的に1行で済むため、キーワードでアニメーションさせるときにもっとも簡単な方法です。
1 2 3 |
:root { interpolate-size: allow-keywords; /* */ } |
このCSSはサポートしていないブラウザではトランジションしないようにフォールバックするので、優れたプログレッシブエンハンスメントにもなります。
計算の実行などより細かい制御が必要な場合は、calc-size()
を使用します。また、calc-size()
にしかできない動作をしようしたい場合も同様です。
1 2 3 4 5 6 7 |
#specific-element { width: 50px; &:hover { width: calc-size(fit-content, size + 1em); /* calc-size()にしかできない計算 */ } } |
ただし、コード内でcalc-size()
を使用すると、calc-size()
をサポートしてないブラウザのためにフォールバックを含める必要があります。たとえば、数値によるサイズ宣言を追加したり、@supports
で機能検出にフォールバックします。
1 2 |
width: fit-content; width: calc-size(fit-content, size + 1em); |
キーワードをアニメーションさせるデモ
:root
にinterpolate-size: allow-keywords;
を設定したデモを見てましょう。
details
要素を使用した開示ウィジェットや排他的アコーディオンを開くときにアニメーションさせます。これにinterpolate-size: allow-keywords;
を使用すると、かなり多くのことが可能になります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
@supports (interpolate-size: allow-keywords) { :root { interpolate-size: allow-keywords; } details { transition: height 0.5s ease; height: 2.5rem; &[open] { height: auto; overflow: clip; /* アニメーション中にコンテンツを切り取る */ } } } |
実際に動作は、デモページでご覧ください。
See the Pen
Styling <details>: Material UI Accordion (interpolate-size version, no ::details-content) by coliss (@coliss)
on CodePen.
通常はウィジェットが開くときのアニメーションは、一方向にしか実行されませんが、interpolate-size: allow-keywords;
と::details-content
を組み合わせると、両方向にアニメーションさせることができます。
※::details-content
は今年後半にChromeに実装予定です。
sponsors