実は難しい! CSSのborder-radiusで実装した角丸を矩形からスムーズにアニメーションさせるテクニック
Post on:2025年3月25日
CSSのborder-radius
で角丸を適用したボックスを拡大・縮小のアニメーションにするとき、最初は鋭角で、拡大したときには角丸になるようにしたいと思ったことはありませんか?
下記のデモはうまく機能していますが、角丸が汚かったり、最初が鋭角の矩形にならなかったり、角丸をスムーズにアニメーションさせる際に遭遇する問題点とその解決方法を紹介します。

Smoothly animating a border-radius
by Bramus!
下記は各ポイントを意訳したものです。
※当ブログでの翻訳記事は、元サイト様にライセンスを得て翻訳しています。
はじめに
ビュー遷移(View Transitions)は、スナップショットをアニメーション化するため、任意の要素を別の要素に変形させることができます。しかし、同じ要素を変形させる場合、スナップショットを使用すると思うように変形できないことがあります。
たとえば、下記のアニメーションをご覧ください。

角丸はborder-radius
で実装されており、これをトランジションさせる場合は、2つのスナップショットがフェードアウトするのではなく、角丸がない状態から角丸がある状態になるように変形されることを望むことがあると思います。
ビュー遷移による問題点
問題点は、ビュー遷移を使用して.card
をモーフィングさせる下記のデモで確認できます。.card
にはview-transition-name
があり、border-radius
を0.25rem
から3rem
までアニメーションさせています。また、それに合わせてfont-size
やaspect-ratio
などのプロパティもアニメーションします。
See the Pen View Transitions with a Border Radius (1/3 – Problem) by Bramus(@Bramus)
on CodePen.
.card
要素の角丸がどのようにモーフィングしているかに注目してください。ビュー遷移はスナップショットをフェードさせるため、border-radius
はきれいに変形されず、古い状態から新しい状態にフェードするだけです。
.card
内のテキストにもview-transition-name
が設定されているので、.card
自体とは別にキャプチャされていることにも注目してください。これは後で重要なポイントになります。
部分的な解決方法
この問題の解決策は、スナップショットを含む::view-transition-group
を操作することです。必要なことは::view-transition-group
にアニメーションを追加することです。上記のデモで言うと、border-radius
のアニメーションです。スナップショットがはみ出さないようにoverflow
でclip
することをポイントです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
@keyframes adjust-border-radius { from { border-radius: 0.25rem; } to { border-radius: 3rem; } } ::view-transition-group(card) { animation-name: -ua-view-transition-group-anim-card, adjust-border-radius; overflow: clip; background: #ccc; } :active-view-transition-type(shrink)::view-transition-group(card) { animation-direction: normal, reverse; } |
adjust-border-radius
のアニメーション(border-radius
のアニメーション)は、既存の-ua-view-transition-group-anim-card
アニメーションに追加します。新しく追加されたアニメーションは、カードが縮小されたときに反転され、ビュー遷移のタイプを使用してJavaScriptからCSSに伝えられます。
これで期待通りに変形されます。
See the Pen View Transitions with a Border Radius (2/3 – Workaround) by Bramus(@Bramus)
on CodePen.
変化する背景への対応
実は上記のデモでは、不正確さをカバーするために、背景色をグループに複製してごまかしています。.card
のbackground-color
も変化させると、この不正確さがはっきりと分かります。
下記のデモでは、角丸に特に注目してください。100%完璧ではないことが分かります。ついでに、カード内のテキストも変更しました。
See the Pen View Transitions with a Border Radius (2/3 – Workaround, with random text) by Bramus(@Bramus)
on CodePen.
ここでの解決策もアニメーションするプロパティを::view-transition-group
に移動することです。この場合はbackground-color
です。
実際に背景がトランジションの一部としてアニメーションするのを実際に見るには、トランジションの実行中はカードを構成するスナップショットを非表示にする必要があります。これは::view-transition-image-pair(card) to display: none;
に設定することで可能です。カードのテキストは別にキャプチャされるため、これは安全に実行できます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
@keyframes adjust-group { from { background: #ccc; border-radius: 0.25rem; } to { background: lightblue; border-radius: 3rem; } } ::view-transition-group(card) { animation-name: -ua-view-transition-group-anim-card, adjust-group; } :active-view-transition-type(shrink)::view-transition-group(card) { animation-direction: normal, reverse; } ::view-transition-image-pair(card) { display: none; } |
実際の動作は、デモページをご覧ください。
See the Pen View Transitions with a Border Radius (2/3 – Workaround, with random text + background animation --fixed) by Bramus(@Bramus)
on CodePen.
要素の前景のスナップショットが背景のスナップショットからはみ出す場合は、border-radius
を複製してそのスナップショットの::view-transition-group
にclip
する必要があります。
将来的には、ネストされたビュー遷移グループによってこの問題は解決されます。ネストは現在Chromeに実装されつつあります。
変化するボーダーへの対応
解決することが難しいのが、ボーダーのアニメーションです。その難しさは、スナップショットがboder-box
を使用して取得されることに由来します。つまり、boder
を::view-transition-group
に複製する場合、スナップショットされた要素のbox-sizing
に関係なく、そのbox-sizing
がborder-box
に設定されていることを確認する必要があります。
この設定があるので、::view-transition-group
にボーダーを安全に複製し、そのキーフレームの一部としてアニメーションさせます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
@keyframes adjust-group { from { border-radius: 0.25rem; background: #ccc; border-width: 2px; } to { border-radius: 3rem; background: lightblue; border-width: 8px; } } ::view-transition-group(card) { box-sizing: border-box; border: 2px solid black; animation-name: -ua-view-transition-group-anim-card, adjust-group; } :active-view-transition-type(shrink)::view-transition-group(card) { animation-direction: normal, reverse; } ::view-transition-image-pair(card) { display: none; } |
実際の動作は、デモページをご覧ください。
See the Pen View Transitions with a Border Radius (2/3 – Workaround, with random text + border) by Bramus(@Bramus)
on CodePen.
終わりに
ビュー遷移の一部としてボーダーなどもスムーズにアニメーションさせるには、そのアニメーションを::view-transition-group
に複製すると解決します。最良の効果を得るには、ビュー遷移がアニメーションさせる要素の背景と前景を別々にキャプチャするようにします。これはそれぞれにview-transition-name
を付与することで可能です。
sponsors