CSSのinterpolate-sizeプロパティを使ったアニメーションの許可



昨今はCSSのみで様々なアニメーションが実装できるようになりましたが、コンテンツ量が変わると多少の調整が必要になる場合もあります。

あらかじめ決まっているコンテンツの要素の幅をアニメーションさせる場合は、transitionプロパティやwidthプロパティの組み合わせで、widthプロパティには決まった数値を指定することでアニメーションが実装できます。
しかし、コンテンツ幅が変化する可能性のある要素をアニメーションさせる場合は、CSSのみでは実装するのが難しいです。

コンテンツ幅が変化する可能性のある要素には、JavaScriptを使って要素の幅を取得してアニメーションさせるなど、少し手の込んだプログラムが必要になります。
ただ、その問題もCSSのinterpolate-sizeプロパティが解決してくれるでしょう。

CSSで「interpolate-size: allow-keywords;」を指定することで、widthプロパティのauto、min-content、max-contentなどの値をCSSアニメーションに適用することができます。
つまり、コンテンツ量に応じた幅に対してアニメーションが実装できるようになります。

「interpolate-size: allow-keywords;」は親要素以上で指定する必要がありますが、様々な要素で必要になることも考えると、ルート要素(:root)に指定するのがベストでしょう。

CSS

:root {
  interpolate-size: allow-keywords;
}


気になるWebブラウザのサポート状況ですが、
2024年10月現在時点では、Google Chrome 129以降のみサポートしています。

Can I use (interpolate-size)
https://caniuse.com/?search=interpolate-size


Google Chromeがサポートされれば、ChromiumベースのMicrosoft Edgeなどもサポートされるので、あとはSafariやFirefoxのサポートを待つのみとなります。

interpolate-sizeプロパティを使ったアニメーションの実装


ここからは、interpolate-sizeプロパティを使ったアニメーションの実装を、サンプルを交えて確認していきます。

サンプルとして、お問い合わせ用のアイコンボタンの動作で見ていきます。
HTMLは以下のような構造を構築します。

HTML

<nav class="contact-nav">
  <ul>
    <li>
      <a href="#">
        <img decoding="async" src="data:image/svg+xml;base64,PCEtLT94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPy0tPgo8IS0tIEdlbmVyYXRvcjogQWRvYmUgSWxsdXN0cmF0b3IgMTguMC4wLCBTVkcgRXhwb3J0IFBsdWctSW4gLiBTVkcgVmVyc2lvbjogNi4wMCBCdWlsZCAwKSAgLS0+Cgo8c3ZnIHZlcnNpb249IjEuMSIgaWQ9Il94MzJfIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB4PSIwcHgiIHk9IjBweCIgdmlld0JveD0iMCAwIDUxMiA1MTIiIHN0eWxlPSJ3aWR0aDogNjRweDsgaGVpZ2h0OiA2NHB4OyBvcGFjaXR5OiAxOyIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSI+CjxzdHlsZSB0eXBlPSJ0ZXh0L2NzcyI+Cgkuc3Qwe2ZpbGw6IzRCNEI0Qjt9Cjwvc3R5bGU+CjxnPgoJPHBhdGggY2xhc3M9InN0MCIgZD0iTTAsNjR2Mzg0aDUxMlY2NEgweiBNMjY0LjEzMiwyNjYuNzY1Yy0xLjk5NiwxLjY4OC00Ljk1LDIuNjU3LTguMSwyLjY1N2MtMy4xNTMsMC02LjA5OC0wLjk2NC04LjA4My0yLjY0MgoJCUw0OCwxMTJoNDE2TDI2NC4xMzIsMjY2Ljc2NXogTTk1LjExLDE5NC4zMDZsNjkuNTE4LDU4Ljk1NEw0OCwzNjhWMTYwTDk1LjExLDE5NC4zMDZ6IE0xOTkuMjg4LDI4Mi42NTJsMTYuMzUsMTMuODY2CgkJYzEwLjgzNiw5LjIxNSwyNS4xNjksMTQuMjg4LDQwLjM2MSwxNC4yODhjMTUuMjM2LDAsMjkuNTg4LTUuMDcxLDQwLjQxOC0xNC4yODJsMTYuMzIxLTEzLjg0Nkw0MzIsNDAwSDgwTDE5OS4yODgsMjgyLjY1MnoKCQkgTTM0Ny4zOTQsMjUzLjI4Mkw0NjQsMTYwdjIwOEwzNDcuMzk0LDI1My4yODJ6IiBzdHlsZT0iZmlsbDogcmdiKDc1LCA3NSwgNzUpOyI+PC9wYXRoPgo8L2c+Cjwvc3ZnPgo=" alt="mail">
        <span class="nav-text">Mail</span>
      </a>
    </li>
    <li>
      <a href="https://bsky.app/profile/akirao.bsky.social" target="_blank" rel="noopener noreferrer">
        <img decoding="async" src="data:image/svg+xml;base64,PCEtLT94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPy0tPgo8IS0tIEdlbmVyYXRvcjogQWRvYmUgSWxsdXN0cmF0b3IgMTguMS4xLCBTVkcgRXhwb3J0IFBsdWctSW4gLiBTVkcgVmVyc2lvbjogNi4wMCBCdWlsZCAwKSAgLS0+Cgo8c3ZnIHZlcnNpb249IjEuMSIgaWQ9Il94MzJfIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB4PSIwcHgiIHk9IjBweCIgdmlld0JveD0iMCAwIDUxMiA1MTIiIHN0eWxlPSJ3aWR0aDogNjRweDsgaGVpZ2h0OiA2NHB4OyBvcGFjaXR5OiAxOyIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSI+CjxzdHlsZSB0eXBlPSJ0ZXh0L2NzcyI+Cgkuc3Qwe2ZpbGw6IzRCNEI0Qjt9Cjwvc3R5bGU+CjxnPgoJPHBhdGggY2xhc3M9InN0MCIgZD0iTTQ0Mi41MzksNzMuOTQ2QzM5Ny43LDM2LjAxOCwzMzMuNTksMTMuODYzLDI1NS4yMDUsMTMuODgxYy03NC4zOTgsMC0xMzcuOTA1LDIwLjk4MS0xODMuMzM3LDU4LjQxMQoJCWMtMjIuNjkyLDE4LjY4Ni00MC43NTgsNDEuNDkxLTUzLjA2LDY3LjQyOEM2LjQ5OCwxNjUuNjQ4LTAuMDEsMTk0LjY0MSwwLDIyNS40MjJjLTAuMDE4LDM3LjIxNCw3Ljc3Nyw3MS41ODYsMjMuNTExLDEwMS41NzcKCQljMTUsMjguNjY0LDM3LjI5OCw1My4wNCw2NS42OTksNzIuMTAzYy02LjcxNSwyOC4yNjktMTYuMTQ4LDY4LjY3LTE2LjE0OCw2OC42ODljLTAuNDMyLDEuODE1LTAuNjU4LDMuNzA2LTAuNjQ4LDUuNjI0CgkJYy0wLjAxOSw3LjU5LDMuNTI2LDE0Ljg5Niw5LjY2OCwxOS42MDhsMC4wMzgsMC4wMjhsMC4wMDksMC4wMWM0LjQwMiwzLjM0OCw5LjcwNiw1LjA2LDE1LDUuMDZjMy45ODcsMCw4LjAzMS0wLjk2OSwxMS42OC0yLjkzNAoJCWwwLjM2Ny0wLjE4OGwwLjM1Ny0wLjIxNmMwLjAxLTAuMDEsNS4wNjktMy4wMSwxMi44NTYtNy42MThjMTEuNjcxLTYuOTAzLDI5LjQzNS0xNy40MDcsNDUuMjkxLTI2Ljc0NQoJCWM3LjkxOS00LjY2NSwxNS4zNjYtOS4wMzgsMjEuMzItMTIuNTA4YzUuOTE2LTMuNDYsMTAuNDc3LTYuMTA0LDEyLjE2LTcuMDM0bDAuMDg1LTAuMDQ3bDAuMTEzLTAuMDY2CgkJYzIyLjEtMTIuNTI2LDM5LjcwNC0xNC42MzMsNTMuODQ5LTE0LjcwOGM1OC42OTItMC4wODUsMTIxLjIxMi0xMS40NjQsMTcxLjEzLTQyLjYyYzI0Ljg5NC0xNS42MDIsNDYuNTYxLTM2LjQxMyw2MS44MDYtNjMuMDU2CgkJYzE1LjI3Mi0yNi42MjQsMjMuODg2LTU4Ljg1MywyMy44NTgtOTYuMTZDNTEyLjEyMiwxNjUuNTQ0LDQ4Ny40MTcsMTExLjc4LDQ0Mi41MzksNzMuOTQ2eiBNNDU0LjcwOSwzMDEuMjQKCQljLTguODEyLDE1LjM3NS0yMC4zNywyOC4zMTYtMzQuMjMyLDM5LjI4MmMtMjAuNzc0LDE2LjQyOS00Ni44NjIsMjguMjg4LTc1LjQ3OSwzNS45MzRjLTI4LjU5OCw3LjY2NC01OS42NDIsMTEuMDg4LTg5Ljc5MiwxMS4wNzgKCQljLTE4LjUxNy0wLjA3NS00NC4zNzksMy40MTQtNzIuNzYxLDE5LjY4M3YtMC4wMDljLTMuMTQsMS43NDktMTAuMTI4LDUuODIyLTE5LjM0NSwxMS4yMTkKCQljLTEzLjIyMiw3Ljc1OS0zMC42MiwxOC4wMTktNDUuMTUsMjYuNjE0YzMuNTQ1LTE1LjA5NCw3LjY1NS0zMi41NzYsMTAuNzMtNDUuNDEzdi0wLjAxOWMwLjUwOS0yLjE0NCwwLjg3NC00LjQ2OCwwLjg4NC03LjExCgkJYzAuMDM3LTMuNzI0LTAuOTIyLTguMjY2LTMuMDc1LTEyLjA0NmMtMS41OS0yLjgzMi0zLjYzOS01LjA2LTUuNDM2LTYuNTgzYy0yLjczNi0yLjI4NS00Ljc5Ni0zLjI3My01Ljk0NC0zLjkwM2wtMS4xNTctMC41OTIKCQlsLTAuMTMxLTAuMDc2Qzg4LjY2NSwzNTMuMDk1LDcwLjE2NiwzMzIuOTcsNTcuNjMsMzA5LjExYy0xMi41MTctMjMuODk2LTE5LjEtNTEuNzgtMTkuMTEtODMuNjg5CgkJYzAuMDEtMjUuNDAxLDUuMjk1LTQ4LjUyNiwxNS4wODUtNjkuMTg4YzE0LjcxOC0zMC45NCwzOS42NjgtNTYuNjA0LDczLjc4Ni03NC44OTZjMzQuMDkxLTE4LjI1NCw3Ny4zOTgtMjguOTM3LDEyNy44MTQtMjguOTM3CgkJYzcxLjI3NiwwLjAxOSwxMjUuOTMzLDIwLjAzMSwxNjIuNDUsNTAuOTUyYzM2LjQ3LDMxLjAyNSw1NS43MDIsNzIuNzk5LDU1LjgyNCwxMjAuODY0CgkJQzQ3My40NTIsMjU1LjcyMyw0NjYuNDE3LDI4MC43MjksNDU0LjcwOSwzMDEuMjR6IiBzdHlsZT0iZmlsbDogcmdiKDc1LCA3NSwgNzUpOyI+PC9wYXRoPgo8L2c+Cjwvc3ZnPgo=" alt="SNS">
        <div class="nav-text">Bluesky</div>
      </a>
    </li>
  </ul>
</nav>


メールでのお問い合わせは、コンタクトフォームを設置しているページなどにリンクさせるといいでしょう。
チャットでのお問い合わせは、ご利用のチャットツールやSNSのDMで手軽にやりとりができるものに。ここでは誰でも簡単に無料でアカウントが作成できるBlueskyをリンクさせてみました。

続いてはCSS。
ルート要素(:root)に「interpolate-size: allow-keywords;」を指定しておきます。
他、お問い合わせのナビゲーションのスタイルを指定します。
以下、CSSのサンプルコードになります。

CSS

:root {
  interpolate-size: allow-keywords;
}

.contact-nav {
  ul {
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
    list-style: none;
    margin: 0;
    padding: 1rem;
    a {
      display: grid;
      grid-template-columns: 1.5rem auto;
      gap: 1rem;
      padding: 0.5rem;
      align-items: center;
      background: #ffd1c6;
      border-radius: 0.5rem;
      text-decoration: none;
      font-size: 1rem;
      color: #333;

      width: 2.5rem;
      overflow-x: clip;
      white-space: nowrap;

      transition: width 0.3s ease;

      &:hover,
      &:focus-visible {
        width: max-content;
        background: #ffab98;
      }
    }
  }
  img {
    width: 1.5rem;
    height: auto;
  }
  .nav-text {
    padding-right: 0.5rem;
    font-weight: bold;
  }
}


今回のサンプルのポイントは、interpolate-sizeプロパティの指定のほか、ul要素のスタイルの部分になります。
リストのa要素のスタイルを見てみましょう。ポイントとなる部分がわかりやすいように、1行空けて記述しています。
「display: grid;」とグリッドレイアウトで構築しています。
grid-template-columnsプロパティで、横方向のグリッド線間の幅を指定します。アイコン部分が1.5rem、残りのコンテンツはautoとします。このときテキスト部分は1.5remからはみ出る状態です。

そしてコンテンツを折りたたんでいる部分は、横幅と切り取りで調整します。
「width: 2.5rem;」でアイコン部分となる幅を調整し、「overflow-x: clip;」でコンテンツを切り取りテキスト部分を非表示とします。
「white-space: nowrap;」は、もし改行したコンテンツを含めたときに、高さが変わった影響でデザインが崩れるので、もしものために指定しておきます。

アニメーションは「transition: width 0.3s ease;」で、横幅を0.3秒かけて変化させています。イージングはお好みの変化を指定してください。

hover擬似クラスまたはキーボード操作時にフォーカスした場合のfocus-visible擬似クラスに対して、横幅を「width: max-content;」とアイコンとテキストを含んだコンテンツの最大幅に指定します。
親要素以上に「interpolate-size: allow-keywords;」が指定してあることで、max-contentでもアニメーションに適用させることができます。

interpolate-sizeプロパティを使ったアニメーションの実装

ちなみに、メニューを画面に固定する場合は、「position: fixed;」などで固定しましょう。
以下のCSSのスタイルと、確認のためにHTML要素も追加しておきます。
(サンプル:画面左中央に固定)

HTML(追加)

<section id="info">
  <div class="section-conts">
  
  </div>
</section>

<section id="about">
  <div class="section-conts">
  
  </div>
</section>


CSS(追加)

.contact-nav {
  position: fixed;
  top: 50%;
  left: 0;
  transform: translateY(-50%);
}

section {
  min-height: 100vh;
  &:nth-of-type(even) {
    background-color: #eee;
  }
}
画面左中央に固定したメニューのアニメーション



infoとaboutのセクションを追加したので、スクロールしても画面左中央にメニューが固定されているのが確認できます。

最後に


今後、CSSのinterpolate-sizeプロパティが多くのWebブラウザでサポートされれば、開閉式のコンテンツやコンパクトなメニューボタンなどを、JavaScriptを使わずCSSのみで手軽に作成することができるでしょう。

ぜひ参考にしてください。