Skip to content

Commit 6c795c0

Browse files
committed
Add initial explainer for calc-size().
1 parent 58350b3 commit 6c795c0

File tree

1 file changed

+236
-0
lines changed

1 file changed

+236
-0
lines changed
Lines changed: 236 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,236 @@
1+
# Explainer: calc-size() function for transitions and animations to/from intrinsic sizes
2+
3+
## Authors:
4+
5+
- L. David Baron ([@dbaron](https://github.com/dbaron)), Google
6+
- Tab Atkins ([@tabatkins](https://github.com/tabatkins)), Google
7+
8+
## Participate
9+
- https://github.com/w3c/csswg-drafts/issues with prefix `[css-values-5]` and @-mentions of authors
10+
11+
## Introduction
12+
13+
Animation to or from auto heights is commonly requested by web developers.
14+
It is important for animation of elements
15+
(such as the contents of disclosure widgets)
16+
opening/closing between a content-based height (or width)
17+
and a small (often zero) height (or width).
18+
This `calc-size()` proposal fits the desire to do such animations
19+
into the way that CSS transitions and animations work.
20+
More generally,
21+
this allows animating
22+
between a fixed length and
23+
almost any type of height (or width, or min/max-height/width)
24+
that can currently be specified in CSS.
25+
26+
The CSS `calc-size()` function is a CSS function similar to calc(),
27+
but that also supports operations on exactly one of the values
28+
auto, min-content, max-content, fit-content, stretch, or contain,
29+
which are the intrinsic sizing keywords.
30+
This allows transitions and animations to and from these values
31+
(or mathematical functions of these values),
32+
as long as the `calc-size()` function is used
33+
on at least one of the endpoints of the transition or animation to opt in.
34+
35+
## Goals
36+
37+
Animations often make it clearer to a user what is changing about a page,
38+
particularly when changes happen in response to a user interaction.
39+
CSS has existing support for animation,
40+
including both [CSS Animations](https://drafts.csswg.org/css-animations-1/), and
41+
[CSS Transitions](https://drafts.csswg.org/css-transitions-1/)
42+
(which are a feature that specifically animations changes to CSS computed values).
43+
44+
CSS also contains features that allow boxes to be sized based on the content;
45+
such sizes are often called intrinsic sizes,
46+
and are represented by keywords such as `auto`, `fit-content`, `stretch`, etc.
47+
The most common example is probably `height: auto`,
48+
which is the initial value of the `height` property.
49+
These features are used by developers to make pages that respond well to
50+
different device characteristics, different user preferences, and different software.
51+
Use of these features makes pages that users can use across more devices and in ways
52+
that better suit the users.
53+
54+
However, currently, CSS does not contain features that allow animating a size to or from
55+
one of these intrinsic sizes.
56+
A common case where such animations are useful are when
57+
a user interface component causes content to appear or disappear.
58+
For example, when a disclosure widget opens,
59+
it can be desirable for the content that appears to animate into existence
60+
by transitioning from zero height to its intrinsic height.
61+
62+
Given this gap in current CSS, developers are forced to limit themselves
63+
to only two out of three of the following:
64+
* using animations of sizes,
65+
* using intrinsic sizes, and
66+
* avoiding javascript in their animations.
67+
68+
(Using javascript to do this sort of animation can often make pages slower
69+
both because computing the correct sizes for the animation requires
70+
forcing extra layouts to happen,
71+
and because efficiently integrating such an animation
72+
with the browser's refresh cycle is tricky.)
73+
74+
The goal of this feature is to remove this limitation and
75+
allow developers to use CSS animate sizes to or from intrinsic sizes.
76+
77+
## Non-goals
78+
79+
It is not a goal of this feature to support animation of a change in size
80+
that results from a change to the element's intrinsic size (for example, when
81+
the content changes and the element becomes taller or shorter as a result).
82+
It is only designed to support animations when the computed value changes.
83+
(This is tied to deeper limitations in CSS's animation model,
84+
and would perhaps be better addressed by a mechanism for layout animations,
85+
though such a mechanism has not yet been clearly described or proposed.)
86+
87+
It is not a goal of this feature to build a new model for animations in CSS.
88+
It is designed to fit in to the existing CSS mechanisms for transitions and animations.
89+
90+
## `calc-size(<basis>, <calculation>)`
91+
92+
The basic form of the proposal is a `calc-size()` function that takes two arguments.
93+
(There is also a one-argument form for convenience; see below.)
94+
The first argument is the *basis* and the second argument is the *calculation*.
95+
It is similar to the existing `calc()` function but is accepted only
96+
for [a small set of CSS properties](https://github.com/w3c/csswg-drafts/issues/626#issuecomment-2025918637)
97+
that relate to sizes.
98+
99+
In addition to the usual mathematical expressions,
100+
the basis also accepts intrinsic sizing keywords.
101+
102+
The basic way the two arguments work is that:
103+
* anything considering the type of the value looks only at the basis,
104+
* anything considering the length resulting from the value looks at the calculation, and
105+
* the `size` keyword can be used in the calculation to substitute in the basis.
106+
107+
In other words, when a CSS-based layout algorithm
108+
(for example, block layout, flex layout, grid layout, table layout, or multicolumn layout)
109+
has something that in pseudocode would be expressed as "if the value is a percentage" or
110+
"if the value is the `fit-content` keyword",
111+
then that pseudocode now examines the *basis* of any `calc-size()` value.
112+
However, when the layout algorithm needs the mathematical value resulting from the value,
113+
then the *calculation* is used.
114+
115+
So, for example, `width: calc-size(min-content, size * 1.5)` makes an element's width
116+
be 1.5 times its `min-content` intrinsic width.
117+
Likewise, `height: calc-size(auto, size * 0.7)` makes an element's height
118+
be 0.7 times its `auto` height;
119+
this would be a normal intermediate value at 70% of the way through an animation from
120+
`0` height to `auto` height
121+
(assuming that one of the values was wrapped in `calc-size()` to opt in to such animation).
122+
123+
This is specified [in css-values-5](https://drafts.csswg.org/css-values-5/#calc-size).
124+
125+
## `calc-size(<value>)`
126+
127+
`calc-size()` also has a single-argument form.
128+
If that single argument is an intrinsic sizing keyword or a `calc-size()` function,
129+
then the argument is treated as the `<basis>` and the calculation is `size`.
130+
Otherwise the single argument is a `<calc-sum>` expression that is treated as the calculation,
131+
and the basis is `any`.
132+
133+
This form makes it more convenient to opt in to animation using `calc-size()`
134+
by wrapping at least one endpoint of the animation in `calc-size()`.
135+
136+
The following slightly more involved example shows
137+
(while using the separately proposed `::details-content` pseudo-element)
138+
the CSS needed to make a `<details>` element
139+
animate its `height` when it opens and closes:
140+
141+
```css
142+
details::details-content {
143+
--open-close-duration: 500ms;
144+
display: block; /* override default 'display: contents' */
145+
height: 0;
146+
transition: height var(--open-close-duration),
147+
content-visibility var(--open-close-duration) allow-discrete step-end;
148+
}
149+
details[open]::details-content {
150+
height: calc-size(max-content);
151+
/* repeat the 'transition' but with 'step-start' (for opening) rather than
152+
'step-end' (for closing) */
153+
transition: height var(--open-close-duration),
154+
content-visibility var(--open-close-duration) allow-discrete step-start;
155+
}
156+
```
157+
158+
This is specified [in css-values-5](https://drafts.csswg.org/css-values-5/#calc-size).
159+
160+
## Detailed design discussion
161+
162+
Much of the design discussion happened in w3c/csswg-drafts#626
163+
starting with
164+
[Tab's comment on 2023-11-06](https://github.com/w3c/csswg-drafts/issues/626#issuecomment-1796541071).
165+
There has also been further discussion in
166+
[w3c/csswg-drafts#10220](https://github.com/w3c/csswg-drafts/issues/10220),
167+
[w3c/csswg-drafts#10259](https://github.com/w3c/csswg-drafts/issues/10259), and
168+
[w3c/csswg-drafts#10294](https://github.com/w3c/csswg-drafts/issues/10294).
169+
170+
## Considered alternatives
171+
172+
### Allowing CSS transitions directly to or from intrinsic size keywords
173+
174+
One alternative that was considered was using `calc-size()` only as a mechanism
175+
for describing the values mid-animation, but still allowing authors to specify
176+
CSS transitions between values such as `0` and `auto`.
177+
178+
This was rejected
179+
because of [compatibility problems](https://github.com/w3c/csswg-drafts/issues/626#issuecomment-2071016522)
180+
it would cause (shown by prototyping it in Chromium).
181+
182+
Currently, using `calc-size()` at at least one of the endpoints of an animation
183+
is required to opt in to animating using `calc-size()` intermediate values.
184+
[w3c/csswg-drafts#10294](https://github.com/w3c/csswg-drafts/issues/10294)
185+
proposes that we consider an additional opt-in mechanism.
186+
187+
### Allowing intrinsic sizing keywords inside of `calc()`
188+
189+
A longstanding proposal for addressing this issue was to allow
190+
CSS intrinsic sizing keywords inside of `calc()`,
191+
and thus allow this sort of animation by
192+
allowing expressions like `calc(10px + 0.5 * auto)`.
193+
194+
This alternative would be more general than the `calc-size()` proposal.
195+
In particular, this allows values that *mix* intrinsic keywords.
196+
On the other hand, the `calc-size()` proposal is intentionally designed
197+
to avoid allowing mixes of different intrinsic keywords.
198+
This is needed to avoid problematic interactions with
199+
many existing layout algorithms specified by CSS,
200+
which follow different behavior for specific intrinsic sizing keywords
201+
or different behavior for values with percentages.
202+
203+
The `calc-size()` proposal avoids these issues by ensuring that
204+
all resulting values can be categorized by their underlying type (or basis)
205+
which is either (a) *one* of the intrinsic sizing keywords,
206+
(b) a `<length-percentage>` value that contains percentages, or
207+
(c) a `<length>` that does not contain percentages.
208+
209+
Animation is only supported between values whose
210+
bases are the same intrinsic sizing keyword
211+
or between values where at least one of the values has
212+
a basis that is not an intrinsic sizing keyword.
213+
This avoids most issues with animation,
214+
although it does have the issue of erasing "percentage-ness"
215+
during an animation between a percentage value and an intrinsic sizing keyword.
216+
(This seems better than disallowing such an animation, though.)
217+
218+
### Other proposals
219+
220+
There were other proposals
221+
in [w3c/csswg-drafts#626](https://github.com/w3c/csswg-drafts/issues/626),
222+
many of which don't integrate well with the model for CSS animations or transitions.
223+
224+
## Stakeholder Feedback / Opposition
225+
226+
- Google: [Positive](https://chromestatus.com/feature/5196713071738880)
227+
228+
## References & acknowledgements
229+
230+
Many thanks for valuable feedback and advice from:
231+
232+
- Oriol Brufau ([@Loirooriol](https://github.com/Loirooriol))
233+
- Rob Flack ([@flackr](https://github.com/flackr))
234+
- Ian Kilpatrick ([@bfgeek](https://github.com/bfgeek))
235+
- Daniil Sakhapov ([@danielsakhapov](https://github.com/danielsakhapov))
236+
- Lea Verou ([@LeaVerou](https://github.com/LeaVerou))

0 commit comments

Comments
 (0)