コハム

Webクリエイターのコハムが提供する、Web制作に役立つ情報をまとめたブログです。

【CSS革命】たった1行のコードで「0→auto」のアニメーションが超簡単に!めっちゃ便利な最新テクニック

Added to my CSS reset: interpolate-size, the quality-of-life feature we all wanted at some point

記事は上記記事を意訳したものです。

※当ブログでの翻訳記事は元サイト様に許可を得て掲載しています。


CSSで、固定幅から子要素によって設定される幅へのトランジションを実現する方法について、私は長年悩まされてきました。StackOverflowなどのプラットフォームで、この質問は何度も繰り返されてきました。max-widthのハックやJavaScriptのソリューションを数えきれないほど使ってきました。もうたくさんです!これからはプログレッシブ・エンハンスメントを全面的に採用します。

この記事では、CSSリセットに新しいinterpolate-sizeプロパティを追加することで得られる利点について説明します。

基本的な実装

以下が、今後私のCSSリセットに追加するCSSスニペットです:

:root {
  @supports (interpolate-size: allow-keywords) {
    interpolate-size: allow-keywords;
  }
}

これは主に新しいプロジェクト向けに追加します。レガシープロジェクトの対応は後で検討します。

この小さなスニペットの効果は、:rootレベルでフラグを設定し、automax-contentmin-contentstretchなどのキーワード値間のトランジションを可能にすることです。

より洗練された言い方をすれば:「固有サイズのキーワードと長さのパーセンテージ間のアニメーションを可能にする」ということです。

執筆時点では、これはChromeでのみ利用可能なため、@supportsフィーチャークエリを追加することをお勧めします。

ボタンのホバーアニメーションの例

button {
  width: 4rem;
  overflow-x: clip;
  transition: width 0.35s ease;
  white-space: nowrap;
  &:is(:hover, :focus) {
    width: auto;
  }
}

このデモは実装が非常にシンプルで、autoキーワードを使用してアニメーションを実現できます。

ケースバイケースの対応:calc-size()関数

古いプロジェクトを保守している場合、デフォルトの動作を変更することに不安を感じるかもしれません。そのような場合、calc-size()関数が有効です:

button {
  &:is(:hover, :focus) {
    width: auto;
    @supports (width: calc-size(auto, size)) {
      width: calc-size(auto, size);
    }
  }
}

現時点ではChromeのみでサポートされていますが、これは「Chromeのみ」ではなく「Chromeファースト」であり、将来的に他のブラウザでもサポートされる予定です。サポートされていないブラウザでは単にアニメーションしないだけなので、ほとんどの場合問題ありません。

キーワードアニメーションの実践的なユースケース

カードのクリックアニメーション

:root {
  @supports (interpolate-size: allow-keywords) {
    interpolate-size: allow-keywords;
  }
}

.image {
  width: 0;
  overflow: clip;
  transition: width 1s ease;
}

.card:has(button[aria-expanded="true"]) .image {
  width: auto; /* expanded時に幅をautoに設定 */
}

.card {
  display: flex;
  max-width: clamp(280px, 80vw, 600px);
}

この例では、.imageラッパーがカードの最大幅に応じてスペースを埋めます。初期状態では幅を0に設定し、オーバーフローをクリップします。ボタンが押されると、.imageラッパーがスペースを埋めるようにauto幅にアニメーションします。

details要素との組み合わせ

Chrome 131で導入される::details-content疑似要素を使用したアコーディオンの実装:

@supports selector(::details-content) {
  ::details-content {
    height: 0;
    transition: padding-block 0.3s, 
                height 0.3s ease,
                content-visibility 0.3s ease allow-discrete;
    overflow: clip;
  }

  details[open]::details-content {
    height: auto;
  }
}

まとめ

プログレッシブ・エンハンスメントを信じ、このシンプルなフラグのオン・オフによって、ブラウザ間で異なる動作を簡単に実現できます。

私は、このCSSリセットまたはリブートにこの設定を追加することを強くお勧めします。ブラウザ間の相互運用性の観点からも、将来的に完全なブラウザサポートを得られることを願っています。

©コハム