Dec 13

calc-size() and interpolate size

It's now possible to animate to or from height: auto and other intrinsic sizes.

By Kevin Powell

Animating to or from height: auto has been something front-end developers have had on their wishlist for a very long time, and now, not only can we do that very easily, but there are new possibilities that have opened up on top of that as well, all thanks to two new CSS features:

All you need is one line of CSS

The new interpolate-size property enables animating to intrinsic sizes, such as auto.

Here’s a simple example of it in action: We go from block-size: 1lh to block-size: auto.

See the CodePen.

Enabling it site-wide with a single declaration

The value of interpolate-size is inherited, so we can enable it across our entire site with a single declaration.

html {
interpolate-size: allow-keywords;
}

That means with a single declaration, you’ve basically opted in to allow transitions and animations using keyword values site-wide!

This is perfect to include this as part of your CSS reset for new projects.

I’ve already started using this in a few places where I need to go from block-size: 0 to block-size: auto, such as with navigations and menus.

See the CodePen.

We can also use this to animate details/summarys, though that also involves using ::details-content, which at the time of writing, has very limited support. Just like calc-size() and interpolate-size, it does make for a great progressive enhancement!

It’s not just for height auto

While animating to and from height: auto might be the most common pain point interpolate-size solves, it also allows us to animate to any of these keyword values:

See the CodePen.

However, you cannot use this to go between two different keyword values, as you can see in this example where it doesn’t work.

See the CodePen.

While that would be cool, I still see this as such a big win that I really don’t mind this one constraint.

You can use animations as well

All of the examples so far have used transitions, but this also opens up using keyword values in animations as well.

For example, instead of simply transitioning open to closed, we can add a nice little bounce effect.

See the CodePen.

Why isn’t this the new default?

There were talks of having this be the default value, but there would be potential conflicts in older sites, such as situations where JavaScript was being used for these types of animations or where assumptions were made knowing transitions wouldn’t work in specific situations.

Because of this, I’d caution against blindly inserting this into older projects. From now on, throw it in that reset and make animations super easy, but I wouldn’t retrofit it into an old project without some testing first.

When you need more fine-grained control

interpolate-size is such a quick win, but you might find yourself running into situations where you want something a little bit bigger or smaller than one of the intrinsic sizes.

calc() doesn’t allow for calculations based on keyword values, but another new addition is calc-size(), which does!

The syntax of calc-size() is a little trickier than that of calc(), but once you get used to it, it’s not so bad.

The reason I say that it’s trickier is that you must pass two values:

Here are some examples:

.height-example {
block-size: calc-size(auto, size + 24px)
}

.width-example {
inline-size: calc-size(max-content, size * .5);
}

In the first example above, I pass the keyword value that I want to do the calculation on (auto), and then after the comma, I say to take whatever size value is computed and add 24px to it.

In the second example, I want the calculation to be based on the max-content of my element and then multiplied by 0.5 so that it becomes half that size.

Here is another simple example.

.max-content {
inline-size: max-content;
}

.bit-bigger-than-max-context {
inline-size: calc-size(max-content, size + 3rem);
}

Preview of applied calc-size() where two text containers are shown, and the second is slightly longer visually due to the calc-size() rule

For a bit more of a practical use case, in the example below, I use position absolute to move an SVG icon out of the flow and offset it to overflow to the right of the button that it is inside of. Then, using calc-size() for the hover and focus states, I can add the distance I’ve offset the icon to the auto size of my button.

See the CodePen.

Animations and transitions with calc-size()

While you might want to use calc-size() for making something slightly bigger or smaller than one of the keyword values, just like interpolate-size, it also opens up animations and transitions on these values as well.

Below, I’ve updated the previous example to add a transition to the inline-size of my button. Because I’m using a calc size(), it works!

See the CodePen.

calc-size() doesn’t require interpolate-size

When you use calc-size(), transitions to and from intrinsic sizes will be allowed regardless of whether you’ve declared interpolate-size: allow-keywords.

You can see that in action in the previous example, where I didn’t declare interpolate-size, and the transition still works.

That means that you could do something like this all on its own, and it’ll work as well:

.transition-height {
height: 1.5lh;
overflow: clip;
transition: height 1s;
}

.transition-height:hover {
height: calc-size(auto, size);
}

However, it is recommended to use interpolate-size for this instead.

It’s easier to simply “turn on” site-wide keyword animations and transitions and then rely on calc-size() when you need to do actual calculations based on keyword values.

Also, it’s worth noting that, just like interpoloate-size: allow-keywords doesn’t work for transtions or animations between keyword values, the same holds true with calc-size().

Using interpolate-size as a progressive enhancement

If interpolate-size is not supported by a browser and you go from block-size: 0 to block-size: auto, the browser will still switch between those two sizes, just without the transition between them. And to me, that makes it a perfect progressive enhancement.

People who are using browsers that support it get a nicer experience, but it won’t cause any issues for anyone using a browser that lacks support.

On the other hand, calc-size() might be something you have to be more careful with, though.

For my buttons above, where I expanded them to show an icon, I wouldn’t really mind if a user didn’t see the icon because it doesn’t give extra value or context to the purpose of the button, but there are times when the extra size you are adding could be important or impact the layout in an important way.

In either case, it probably is a bit of a case-by-case basis, but I do think most cases of interpolate-size would be fine. You might either have to think about it or provide alternatives with a @supports feature query for calc-size().

Kevin Powell

Kevin Powell

Do my best to help people fall in love with CSS 😊

Kevin selected CHU Sainte-Justine Foundation for an honorary donation of $50

CHU Sainte-Justine Foundation

Support CHU Sainte-Justine in its pursuit of excellence and its commitment to providing children and mothers with one of the highest levels of health care in the world, now and in the future.