calc-size()
Experimental: This is an experimental technology
Check the Browser compatibility table carefully before using this in production.
The calc-size()
CSS function allows you to perform calculations on intrinsic size values such as auto
, fit-content
, and max-content
; this is not supported by the regular calc()
function.
calc-size()
return values can also be interpolated, enabling size keyword values to be used in animations and transitions. In effect, including calc-size()
in a property value automatically applies interpolate-size: allow-keywords
to the selection.
Note however that interpolate-size
is inherited, therefore applying it to an element enables interpolation of intrinsic size keywords for every property applied to that element and its children. As a result, interpolate-size
is the preferred solution for enabling intrinsic size animations. You should only use calc-size()
to enable intrinsic size animations if they also require calculations.
Syntax
/* Pass a value through calc-size() */
calc-size(auto, size)
calc-size(fit-content, size)
/* Perform a calculation */
calc-size(min-content, size + 100px)
calc-size(fit-content, size / 2)
/* Calculation including a function */
calc-size(auto, round(up, size, 50px))
Parameters
The calc-size()
function's syntax is as follows:
calc-size(<calc-size-basis>, <calc-sum>)
The parameters are:
<calc-size-basis>
-
The value (most commonly an intrinsic size) that you want to perform a calculation on.
<calc-sum>
-
An expression that defines the calculation to be performed on the
<calc-size-basis>
.
Return value
Returns a value equal to the <calc-size-basis>
modified by the <calc-sum>
expression. As the <calc-size-basis>
value is an intrinsic size value, the return value is a modified intrinsic size value that behaves like the intrinsic size value input into the function.
Description
Certain browser layout algorithms have special behaviors for intrinsic sizing keywords. The calc-size()
function is explicitly defined to represent an intrinsic size rather than a <length-percentage>
, thereby enforcing correctness. calc-size()
enables calculations to be performed on intrinsic size values in a safe, well-defined manner.
Valid values for the first argument (<calc-size-basis>
)
The first calc-size()
argument can be one of the following intrinsic values:
auto
min-content
max-content
fit-content
content
(for containers sized usingflex-basis
).
There are also a few special values that this argument can take:
-
A nested
calc-size()
value. This isn't something you'd be likely to do very often, but it is available ensuring using a CSS variable as the<calc-size-basis>
will always work, provided the variable is a valid value for the propertycalc-size()
is being set on. So for example, this will work:csssection { height: calc-size(calc-size(max-content, size), size + 2rem); }
As will this:
css:root { --intrinsic-size: calc-size(max-content, size); } section { height: calc-size(var(--intrinsic-size), size + 2rem); }
-
Another
<calc-sum>
, with the same restrictions as the<calc-sum>
specified for the second argument, except that thesize
keyword cannot be included. You likely will not do this, as you are no longer doing a calculation on an intrinsic size value, but if a custom property value is a<calc-sum>
, the function will still work. For example, this will work directly or if you use a custom property with a value of300px + 2rem
:csssection { height: calc-size(300px + 2rem, size / 2); }
-
The keyword
any
, which represents an unspecified definite size. In this case, thesize
keyword cannot be included in the second argument, and thecalc-size()
returns the result of the second argument calculation. For example:csssection { height: calc-size(any, 300px * 1.5); /* Returns 450px */ }
Mixing different intrinsic sizes together in the same calculation doesn't work. For example, max-content - min-content
doesn't make sense. calc-size()
only allows a single intrinsic size value in each calculation, avoiding this problem.
Valid values for the second argument (<calc-sum>
)
The second calc-size()
argument is a <calc-sum>
expression.
In this expression:
- The keyword
size
represents the<calc-size-basis>
specified as the first argument. - Operands can include
size
, and any value types that make sense in the context. - The
+
,-
,*
, and/
operators can be included. - Other mathematical functions can be included such as
round()
,max()
, or even a nestedcalc-size()
. - The overall expression must match
<length-percentage>
, and resolve to a<length>
.
Enabling animation of intrinsic size values
calc-size()
return values can be interpolated, enabling animations between a <length-percentage>
value and a calc-size()
intrinsic size return value.
Note: You should avoid animating box model properties if possible, to cut down on layout events and mitigate the resulting impact on performance (see Critical rendering path > Layout).
For example, you could use a transition to animate a container width
between 0
and auto
like so:
section {
width: 0;
transition: width ease 1s;
}
section:hover,
section:focus {
width: calc-size(auto, size);
}
In the above case, we are not calculating anything — we are putting auto
into calc-size()
and returning it unchanged. The interpolate-size
property makes animations like the above simpler to implement in most cases, especially when there are multiple animations to consider. It is inherited and therefore only needs to be declared once on an ancestor property, meaning we could have transitioned between 0
and auto
without using calc-size()
.
The calc-size()
function should only be used to enable intrinsic size animations if they also require calculations. For example, in the following case we are animating the width
and applying a calculation to the intrinsic size end state:
section {
width: 0;
transition: width ease 1s;
}
section:hover,
section:focus {
width: calc-size(auto, size + 2rem);
}
One case in which calc-size()
is useful is when you want to animate between an intrinsic size and a modified version of the same intrinsic size. This is not possible with interpolate-size
and calc()
. For example, the following @keyframes
definition animates a container width
between fit-content
and 70% of the fit-content
.
@keyframes narrower {
from {
width: fit-content;
}
to {
width: calc-size(fit-content, size * 0.7);
}
}
Note:
Note that calc-size()
does not enable animating between two different intrinsic size values.
Formal syntax
<calc-size()> =
calc-size( <calc-size-basis> , <calc-sum> )
<calc-size-basis> =
<intrinsic-size-keyword> |
<calc-size()> |
any |
<calc-sum>
<calc-sum> =
<calc-product> [ [ '+' | '-' ] <calc-product> ]*
<calc-product> =
<calc-value> [ [ '*' | '/' ] <calc-value> ]*
<calc-value> =
<number> |
<dimension> |
<percentage> |
<calc-keyword> |
( <calc-sum> )
<calc-keyword> =
e |
pi |
infinity |
-infinity |
NaN
Examples
Basic calc-size
usage
This example shows basic dimension sizing of a container using calc-size()
HTML
The HTML contains a single <section>
element that contains some child content.
<section>
<h2>Favorite quote</h2>
<p>
Fashion is something so ugly it has to be changed every fifteen minutes.
</p>
</section>
CSS
In the CSS, we use flexbox to center the child elements inside the <section>
, and set thewidth
and height
of the <section>
to calc-size()
functions. The width
is set equal to fit-content
plus 6rem
. The height
is set to auto
multiplied by two.
section {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
width: calc-size(fit-content, size + 6rem);
height: calc-size(auto, size * 2);
}
The rest of the CSS has been hidden for brevity.
Result
We've created some horizontal and vertical space for the text to be centered in, without the use of padding.
Basic calc-size
animations
This example demonstrates how to use calc-size()
to animate between a specific size and an intrinsic size. The demo features a character badge/"name tag", which can be hovered or focused to reveal information about the character. The reveal is handled by a height
transition between a set length and max-content
.
HTML
The HTML contains a single <section>
element with tabindex="0"
set on it so it can receive keyboard focus. The <section>
contains <header>
and <main>
elements, each with their own child content.
<section tabindex="0">
<header>
<h2>Chris Mills</h2>
</header>
<main>
<p>Chris is the silent phantom of MDN.</p>
<ul>
<li><strong>Height</strong>: 3.03m</li>
<li><strong>Weight</strong>: 160kg</li>
<li><strong>Tech Fu</strong>: 7</li>
<li><strong>Bad Jokes</strong>: 9</li>
</ul>
</main>
</section>
CSS
In the CSS, we set the <section>
's height
to 2.5rem
and overflow
to hidden
so only the <header>
is shown by default, then specify a transition
that animates the <section>
height
over 1 second during state changes. Finally, we set the <section>
height
to a calc-size()
function call on :hover
and :focus
. The function return value is the equivalent of max-content
+ 2rem
.
section {
height: 2.5rem;
overflow: hidden;
transition: height ease 1s;
}
section:hover,
section:focus {
height: calc-size(max-content, size + 2rem);
}
The rest of the CSS has been hidden for brevity.
Result
Try hovering over the <section>
or focusing it via the keyboard — it will animate to its full height + 2rem, revealing all the content with 2rems of extra space at the bottom.
Adjusting reading width based on fit-content
This example shows a container with text inside it, and a button that can be clicked to make the container width narrower or wider depending on reading preference.
HTML
The HTML contains a single <section>
element containing child text content, plus a <button>
to change the <section>
width.
<section class="easy-reader">
<h2>Easy reader</h2>
<p>
Eius velit aperiam ipsa. Deleniti eum excepturi ut magni maxime maxime
beatae. Dicta aperiam est laudantium ut illum facere qui officiis. Sunt
deleniti quam id. Quis sunt voluptatem praesentium minima dolorum autem
consequatur velit.
</p>
<p>
Vitae ab incidunt velit aspernatur deleniti distinctio rerum. Et natus sed
et quos mollitia quia quod. Quae officia ex ea. Ducimus ut voluptatem et et
debitis. Quidem provident laboriosam exercitationem similique deleniti.
Temporibus vel veniam mollitia magni unde a nostrum.
</p>
<button class="width-adjust">Narrower</button>
</section>
CSS
In the CSS, we set the <section>
's width
to a default of fit-content
. We then define two sets of @keyframes
, narrower
, which animates from fit-content
to 70% of fit-content
(calculated using calc-size()
), and wider
, which animates the same values but in the opposite direction. Finally, we attach those animations to two classes — .narrower
and .wider
. Each animation is defined to last one second and to keep the final state applied once finished.
section {
width: fit-content;
}
@keyframes narrower {
from {
width: fit-content;
}
to {
width: calc-size(fit-content, size * 0.7);
}
}
@keyframes wider {
from {
width: calc-size(fit-content, size * 0.7);
}
to {
width: fit-content;
}
}
.narrower {
animation: narrower 1s ease forwards;
}
.wider {
animation: wider 1s ease forwards;
}
The rest of the CSS has been hidden for brevity.
JavaScript
The JavaScript provides a narrower/wider toggle that applies the relevant class to the <section>
when the button is clicked:
const widthAdjustBtn = document.querySelector(".width-adjust");
const easyReader = document.querySelector(".easy-reader");
widthAdjustBtn.addEventListener("click", () => {
if (easyReader.classList.length === 1) {
easyReader.classList.add("narrower");
widthAdjustBtn.textContent = "Wider";
} else if (easyReader.classList.contains("wider")) {
easyReader.classList.replace("wider", "narrower");
widthAdjustBtn.textContent = "Wider";
} else if (easyReader.classList.contains("narrower")) {
easyReader.classList.replace("narrower", "wider");
widthAdjustBtn.textContent = "Narrower";
}
});
Result
Try clicking the <button>
a few times to adjust the <section>
between the wide and narrow reading width, achieved by manipulating the width
based on the fit-content
value.
Using a function inside the calc-size()
function
As mentioned earlier, it is possible to use another function inside calc-size()
. This example sets field-sizing: content
on <input>
elements to make them as wide as the entered content, and then uses a max()
function inside calc-size()
to ensure that the <input>
s are at least a minimum size, and only start to grow when the entered text becomes wider than that size — by being set to fit-content
plus 20px
.
HTML
The HTML contains a <form>
element containing three textual <input>
types. Each <input>
has a <label>
associated with it to make the form accessible, and a maxlength
applied to stop entered values getting long enough to break the form layout.
<form>
<div>
<label for="name">Name:</label>
<input type="text" id="name" name="name" maxlength="48" />
</div>
<div>
<label for="email">Email:</label>
<input type="email" id="email" name="email" maxlength="48" />
</div>
<div>
<label for="address">Address:</label>
<input type="text" id="address" name="address" maxlength="60" />
</div>
</form>
CSS
In the CSS, we set the width
of the <label>
elements to 100px
. We set field-sizing: content
on the <input>
elements to make them as wide as the entered content — by default they would no width because nothing would be entered into them. To counteract this, we set their width
values to calc-size(fit-content, max(100px, size + 20px))
. This means that they are a minimum of 100px
wide, even with no value entered. When an entered value becomes wider than 100px
, their width
changes to fit-content
plus 20px
, which means they start to grow with the content size but keep a 20px
gap on the right-hand side.
label {
width: 100px;
}
input {
field-sizing: content;
width: calc-size(fit-content, max(100px, size + 20px));
}
The rest of the CSS has been hidden for brevity.
Result
Try entering some text inside the form inputs, and see how they grow when the values start to become as wide as the minimum width enforced by the max()
function.
Specifications
Specification |
---|
CSS Values and Units Module Level 5 # calc-size |
Browser compatibility
BCD tables only load in the browser
See also
interpolate-size
calc()
round()
- Animate to height: auto; (and other intrinsic sizing keywords) in CSS on developer.chrome.com (2024)