w3c / csswg-drafts

CSS Working Group Editor Drafts
https://drafts.csswg.org/
Other
4.43k stars 656 forks source link

[css-transitions] Transition to height (or width) "auto" #626

Open keithjgrant opened 7 years ago

keithjgrant commented 7 years ago

(Edited: current resolved-on proposal is at https://github.com/w3c/csswg-drafts/issues/626#issuecomment-1800254442)

https://drafts.csswg.org/css-transitions/#animtype-rect

It would be incredibly useful to be able to transition to (or from) height: auto. As it stands now, you need to jump through a bunch of hoops in JavaScript to simulate it. This is used frequently for transitioning in alert boxes, opening accordions, etc, but it seems silly that JavaScript is required.

I’m sure there must be discussion about this in the old mailing list, but I’d love to be privy to it here.

danegraphics commented 3 years ago

We all agree that the use of 'auto' in animations should just be a single static value calculated for the property before the animation begins. And in most cases (the ones that matter), this would be the perfect solution.

And for good measure, you could have the value of 'auto' recalculate once when the animation is finished just in case something changed about the environment. Sure, that might look janky in some rare cases, but it's certainly better than not being able to transition to 'auto' at all.

Heck, we don't need 'calc(auto)' yet (and maybe not ever). We just need transitions to and from 'auto'.

Regardless of how it's solved, this is a problem that has going on for far too long and needs to be addressed as soon as possible, and it needs to start with the spec.

As it's been stated before, this is one the most requested features in CSS (perhaps THE most requested), has been for over 5 years now, and it's still perhaps the only requested feature that doesn't have any good alternative solutions.

We gotta put it in the spec.

benbucksch commented 3 years ago

Here's a simple attempt at a trivial first draft (browser implementors, please feel free to adjust):

  1. If an element has a CSS animation on height and its height changes to auto, calculate the height that the element would have with height: auto, and remember the value as targetValue.
  2. Remember the current height value as startValue, and start the CSS animation from the startValue to the targetValue, i.e. use the interpolation function between these 2 static values.
  3. If the viewport size or other page elements change, and they would cause a change of the element height in case of auto, set that value as the new targetValue, and continue the animation from the current absolute height to the new targetValue. In other words, add an onresize event listener on the element and re-run from step 1. (Non-linear interpolation interpolation functions continue at the percentage where it left off, i.e. if the resize happened at 40% completion, the restart continues at 40% as well, with the startValue adapted correspondingly, i.e. divide it by 60%.)
  4. Once the CSS animation finishes, height behaves like a normal auto, but the size change handler from step 3 stays in place, until height is no longer set to auto.

"height" in the description above may be replaced with width or any similar CSS property that can have a value of auto and can have CSS animations.

(If you're not a browser implementor, please resist the urge to fine-tune and tweak the above draft, otherwise it will get lost in the flood of comments and browser implementors will not even read this thread. This is not to say that the above spec is perfect, it's just a matter of focus.)

Loirooriol commented 3 years ago

That's not consistent with how transitions involving percentages react to page changes that affect the resolved value, as I mentioned in https://github.com/w3c/csswg-drafts/issues/626#issuecomment-631050968

Rather than special-casing auto in some hacky and inconsistent way, I would probably prefer to have something like transition-property: used(height), which would transition used values instead of computed ones. No need to define calc(auto), then, since the used value is a length. This would also benefit other properties, like if you have line-height: normal; transition: used(line-height) 1s; and then the font changes, the line height will transition smoothly even if the computed value stays as normal.

That said, I don't think that used values are always well defined in the specs, so this would also be a big work. May not be easy to implement either. And being based on used values means that implementations will have to perform layout in order to calculate them, so it seems more expensive.

birtles commented 3 years ago

(I agree we should fix this but bear in mind that animations of height are generally going to trigger layout updates on every frame so they're likely to suffer performance issues, particularly on lower-end devices.

They'll probably be fine for many minor animations but for any animations covering more than a few frames/pixels you'll be better off re-thinking the animation in terms of transform / opacity animations. It's a lot more work but the result will be better.

Like @Loirooriol one day I'd love to see browsers have a more general means of transitioning between layouts. That could solve this issue and others in a performant way.)

eoghanmurray commented 3 years ago

[agreeing with recent comments from jstsch, benbucksch & danegraphics ] I think those who could solve this issue on this thread are perhaps thinking too generally.
I'd say it would solve 95% of the problems that people are having if there could be a transition to auto which worked when overflow:hidden; is set. There are no internal layout updates in this case, and as far as my knowledge extends, no need to require calc to accept the auto keyword (correct me if I'm wrong, but with overflow:hidden, we are really just animating to the value equivalent to the javascript el.scrollWidth or el.scrollHeight?). Would it be desirable to special-case the overflow:hidden case?

eoghanmurray commented 3 years ago

@Loirooriol

What happens if you have height: calc(auto + 5px); align-self: stretch?

Thinking about this some more, this kind of confirms to me that auto shouldn't be permissable in calc. For me auto is an instruction to the CSS engine to 'do what you would have done'. As an author it shouldn't be expected that I have to reason about how auto works, i.e. what auto + 5px means or how it should combine; which if it is not obvious to implementers, would definitely be non-obvious to authors. calc(100% + 5px) makes sense to me (as an advanced user), as 100% is a unit, whereas auto is an instruction. That doesn't mean transitioning to auto shouldn't work, just that it should mean "calculate the size you would have calculated had auto been applied immediately, and then interpolate to that size over the intervening time". (So basically @benbucksch's sketch of the algorithm)

eoghanmurray commented 3 years ago

@birtles

you'll be better off re-thinking the animation in terms of transform / opacity animations. It's a lot more work but the result will be better.

No, this completely misses the point. The reason people want to transition the height is that they want to reclaim the layout space for other elements when the item is 'contracted'. This is why the max-height hack is in place all over the web. And transitions are really important when doing this sort of thing so that the website visitor can see the layout change taking place as otherwise they are in danger of 'losing their place' when a jarring immediate jump takes place.

birtles commented 3 years ago

The reason people want to transition the height is that they want to reclaim the layout space for other elements when the item is 'contracted'.

Right, so there are a number of ways to cover this.

A common one is to cache the bounding box top of each element in your container. Then, when you contract the item, you read off the updated bounding box top of each element later in the flow (and in the viewport) then add a transform animation to animate them from where they were to their new position.

It's quite a bit of work and sometimes you need to clamp the container height until the animation finishes but it's performant and you can stagger the transform animations to produce a more organic effect. By that point, though, you often want to use Web animations or the like because you can get away without forcing style flushes in order to trigger the effect.

I still animate the height for small animations though because it's so much easier and transitions have really nice interrupting behavior.

danegraphics commented 3 years ago

It feels like we've gotten a little off topic, so I will summarize the main points.

  1. Designers desire the ability to transition to and from the auto value for a myriad of properties, height and width especially. This is an extremely common desire among designers.
  2. Currently, there is no way to do this efficiently or smoothly. Even the javascript work arounds are janky and laggy at best.
  3. We need to avoid issues where the layout changing during the animation may change the value of auto during the animation as well.
  4. The most agreed upon solution so far has been to evaluate autos numerical value at the beginning of the animation, use it for the animation, and keep that value static until the end, at which point the property is simply set to auto.
  5. There is no need to allow calc() to evaluate auto, and many agree that it should probably be avoided given that it introduces paradoxes of interpretation.

Given this summary, I'd say we're making good progress in determining at least a general plan. Is there something I may have missed or forgotten in this summary?

MortezaMirmojarabian commented 2 years ago

+1 👍 For now, we can use height: 100%, top, or the flex property in grid and flex layouts: https://stackoverflow.com/a/69871346/478018

SetTrend commented 2 years ago

I'd like to bring this issue back our attention, after it being open for more than 5 years now.

pinksynth commented 2 years ago

Just an idea: What if there was a keyword for height (and other properties) that behaved like auto, but was a separate keyword which was intended for this purpose specifically:

.item.collapsed {
  height: 20px;
}

.item.expanded {
  height: auto-transitionable; /* probably a better name than this */
}

Just wondering if this would make it possible to implement the desired height transition without having to immediately implement all the other things (calc(), etc) which make the change to auto prohibitively challenging. It could be a known constraint of auto-transitionable that it is quirky and shouldn't be used with calc(), etc, and shouldn't really be used except to achieve this specific use case. Even if the proposal is kludgey, I would prefer one line of kludgey CSS over a thousand kludgey JS workarounds.

My apologies if this isn't a constructive proposal, as I am not very familiar with the process by which features are integrated into CSS.

Loirooriol commented 2 years ago

Adding something that behaves like auto and is interpolable doesn't sound easier than making auto interpolable, though?

pinksynth commented 2 years ago

I'm not sure. My understanding based on the descriptions above was that the issue with making auto transitionable is that auto has to follow a bunch of other rules (calc()). Abstractly, I'm thinking the proposed keyword would only follow the rules necessary to achieve this transition feature without following those other rules like calc(). Not full interoperability. Hope that makes sense.

Loirooriol commented 2 years ago

auto doesn't work in calc(). But making auto (or auto-transitionable) interpolable would probably need that, since interpolating from a to b at t∈[0,1] is basically calc(a*(1-t) + b*t) https://drafts.csswg.org/css-values/#combine-dimensions

pinksynth commented 2 years ago

I respect that for reasons that go a little bit deeper, this is a pretty complicated request.

To quote @rickyp-ms,

What can we do as the larger software development community to petition this change and make sure it gets in on the next iteration?

There are clearly lot of people who want to voice their desire for this to be a reality. What can we do to show the working group that we want this particular feature more than anything else?

eoghanmurray commented 2 years ago

@AmeliaBR :

intermediary states can usually be described via a calc() function. 10% of the transition from 50px to 20em is calc(0.950px + 0.120em)

This is very informative. However @Loirooriol has implied that having auto supported in calc is a prerequisite for the transition to auto, however, I don't believe this follows. Everyone would be happy if a pixel value were calculated for auto at the start of the transition, and that this fixed value is plugged in to the above calc formula to generate an interpolated value at each time step.

Loirooriol commented 2 years ago

Everyone would be happy if a pixel value were calculated for auto at the start of the transition

That's not how the current model works, it's based on computed values. Yes, we could add a different model based on used values, but probably not trivial. I already said this in https://github.com/w3c/csswg-drafts/issues/626#issuecomment-841852311

danegraphics commented 2 years ago

@Loirooriol I don't understand your description of "the current model". Does the current model not interpolate between two values? Could it not interpolate between two precomputed values?

What we're saying is that instead of making auto usable in calc, simply make auto transitionable on its own. At the start of a transition to or from auto, simply precompute the value of auto and use the precomputed value to interpolate to or from.

SetTrend commented 2 years ago

I don't want to be wise here, but would it make sense to have an imperative dependeny roadmap of what needs to be done in order to get this feature request working?

Would someone of the contributors want to create a roadmap of what items need to be touched (and what exactly needs to be touched for each of the items) in order to finally have the gates open for implementing this feature?

Loirooriol commented 2 years ago

Does the current model not interpolate between two values?

@danegraphics It interpolates between two computed values. If we introduce interpolation with a computed auto, then we can use auto in calc() for free. If the interpolation is with the used amount of pixels that result from auto, then it's a different model which is not based on computed values.

create a roadmap of what items need to be touched (and what exactly needs to be touched for each of the items)

@SetTrend I guess this depends on the approach: either making auto interpolable, or adding a way to transition between used values instead of computed values. Anyways, I'm not an expert in animations, so not the right person to provide the details.

eoghanmurray commented 2 years ago

@Loirooriol Thanks for your patience and for linking back to previous discussion.

Is the following an outline algorithm of "introducing interpolation with a computed auto"?

  1. if you've got transition:height; on an element, save the current height as 'old_height' just before any changes are made to the element
  2. if the new height is set to auto, apply the change in a 'virtual area' which doesn't affect layout yet. Use this to calculate a 'new_height'
  3. apply the change in the DOM, but with the override height of 'old_height' initially
  4. run the transition through to the 'new_height' according to the transition

I imagine the difference of this from the current spec is that in step 1 you don't calculate the old_height, you just look it up from the CSS (is this what you mean by 'used value')? And also there's currently no attempt to pre-calculate the layout to derive the final value? Rather than solve the general case, I definitely think this should be limited in scope to when an explicit auto is added or removed to the CSS. It could be extended to other cases upon demand, and based on whether they are sane!

Is there ongoing work on a draft for the above? Or a draft for the other approach you mentioned?

Aside: This might work for the image being replaced by a differently sized one with transition:height set on the container, but I can already think of complications to that, and that's not what this ticket is about — a transition wouldn't apply in that case according to this proposal as auto hasn't been added or removed when the image is changed.

Loirooriol commented 2 years ago

Storing (and not updating) the amount of pixels looks more like interpolating used values. Imagine you interpolate from height: auto (which resolves to 0px) to height: 200px. At 50% with linear easing, the height should be (0px + 200px) / 2 = 100px. But then if you add some contents that would make auto resolve to 50px, then the height should immediately become (50px + 200px) / 2 = 125px, if the approach is based on computed values. That would be consistent with what happens when interpolating a percentage and changing the size of the containing block.

Basically, for interpolating between a computed auto and a <length-percentage>, we need to define how to treat a math expression like (1 - t) * auto + t * <length-percentage>. And at that point I'd just add full support for auto in calc(), e.g. things like calc(2 * auto), calc(auto + 100px), etc. With the expectancy that calc(auto + 0px) should be equivalent to auto, and calc(0*auto) should be equivalent to 0px. The difficult part is that various things (like stretch) depend on whether the computed value is auto, what to do if it's a mix?

danegraphics commented 2 years ago

@Loirooriol

If the interpolation is with the used amount of pixels that result from auto, then it's a different model which is not based on computed values.

What do you mean by that? Would the computed value of auto not be a pixel value?

eoghanmurray commented 2 years ago

But then if you add some contents that would make auto resolve to 50px

So I also had a step 5. that I omitted for simplicity as I didn't think it applied to the simpler case:

  1. if the contents change during the transition, then restart from step 1, but during step 2. omit any transitional value when calculating the new auto

But I'm not sure that addresses your case.

then the height should immediately become (50px + 200px) / 2 = 125px

Hmmm, I'm struggling to understand this; if an explicit height is set to 200px, then shouldn't the final value remain at 200px? So no adjustment needs to be made to the ongoing transition? I can't think of a layout example where an explicit height adds to the height derived from the content?

Loirooriol commented 2 years ago

@danegraphics No, auto computes as specified, not as a length (https://www.w3.org/TR/css-sizing-3/#preferred-size-properties). Resolving it as a length needs layout, at computed-value time it's too early.

@eoghanmurray Yes, if the final height is 200px, it should remain as the final value. It's just that the starting point now resolves to 50px, and we are half-way, so the resolved current value should suddenly change from 100px to 125px. Then the transition should continue from 125px to 200px. See https://software.hixie.ch/utilities/js/live-dom-viewer/saved/10080 which uses percentages, imagine that height: 100% is height: auto, and that instead of changing size of the container I'm changing the contents.

eoghanmurray commented 2 years ago

the resolved current value should suddenly change from 100px to 125px

Ok, this initially sounded confusing, as it's not immediately apparent to me why this should be desired behaviour, but I guess you are saying that because there is currently a jump if content is added to a container, therefore there should also be a jump if content is added during the transition. Note: this isn't the current behaviour with explicit transitions; https://software.hixie.ch/utilities/js/live-dom-viewer/ but I accept the behaviour needs to be defined for when the value which was initially computed for auto changes during transition. You've likely been arguing that this is the crux of the point all along?

There are two solutions I can see: A) after finishing the transition, recalculate what auto should be; the jump may happen then (if extra content has been added and the height computed for auto is now larger) B) if contents change during transition then recalculate auto, and replace the value fed into that calc(a*(1-t) + b*t) function (note I still don't think that you need to add spec-level support for auto within calc) .. the correct jump should happen then.

I imagine this is not the type of thing that you'd want left undefined? If so have I think B) is the desired behaviour (I think most here wouldn't care whether it's A or B). B) may well be easier if auto was calcable, but from reading about the problematic edge cases that you mentioned, I'm not fully convinced whether support for something like height: calc(auto + 5px); align-self: stretch would ever be desirable; if you can't easily explain it then should it be supported?

Have I convinced you that B) is doable without having to support auto in calc and that it's desirable to push that through well before any more general case support for auto within calc?

Loirooriol commented 2 years ago

it's not immediately apparent to me why this should be desired behavior

Not necessarily desired, just a corollary of using computed values. If you are at midway between 100% and 200px, that's 50% + 100px. If the 50% was resolving to 0px, then we had 0px + 100px = 100px. But if something changes and 50% now resolves to 25px, then we have 25px + 100px = 125px. And this is a sudden visual change because we are interpolating computed values, and the computed value is not affected, it's still 50% + 100px.

In some cases you may not desire this, that's why I said we could add a new way to interpolate used values instead of computed values, which would cover these usecases, and also auto.

It seems you are also thinking in terms of a used value interpolation. So rather than trying to interpolate auto by internally switching to a used-value interpolation with various hacks to make it seem closer to a computed value interpolation, I would prefer to explicitly add a way for authors to request a used-value interpolation without hacks.

B) is doable without having to support auto in calc

Sure, if interpolating used values, but that's a new thing that would need to be properly designed and defined.

But keeping the current model based on computed values, then we need a*(1-t) + b*t with auto, and if we can do that it should be trivial to fully allow auto in calc().

danegraphics commented 2 years ago

@Loirooriol

Resolving it as a length needs layout, at computed-value time it's too early.

Then we should resolve it as a length. When we are talking about the "computed" value of auto, we are talking about the final pixel/length value of the layout with auto applied. Essentially, we want to calculate and transition to an equivalent final value, and then replace that with auto when the transition finishes. We do not care about any values that do not result in the final layout resulting from using auto.

And if the final value of auto changes during the transition, we would simply rather ignore it. In the overwhelming majority of cases, it will not change during the transition. And the few cases where it does change during transition will be cases where it is okay if it snaps to the new value afterward (say, someone resizing the window, or content updating, or whatever).

SetTrend commented 2 years ago

@Loirooriol:

Looking at what happens to a transition from value [a] to [b], focussing on when one of the two values changes, there are two cases to consider here:

  1. [a] = auto  to  [b] = fixed value
  2. [a] = fixed value  to  [b] = auto

So, if the computed value of auto changes while a transition is active, it's the same as when a fixed value would change.

Given this example:

p   /* rule #1 */
{
  height: 10em;
  transition: height 2s;
}

p:hover   /* rule #2 */
{
  height: 20em;
}
  1. what would happen if rule #1 changed to, e.g., height: 15em;
  2. what would happen if rule #2 changed to, e.g., height: 15em;

… during a transition?

(… or if the font size changed during a transition?)

The same rules should apply to auto.

Moreover, if this thought took roots, the following (currently invalid transition) should become valid, too:

p   /* rule #1 */
{
  height: 10px;
  transition: height 2s;
}

p:hover   /* rule #2 */
{
  height: 20em;
}

(Please note the different units used in both rules.)

… and this should also become valid:

p   /* rule #1 */
{
  height: 0;
  transition: height 2s;
}

p:hover   /* rule #2 */
{
  height: 20em;
}

(Please note the missing unit in rule #1.)

Loirooriol commented 2 years ago

what would happen if rule #n changed

Transitions happen when the computed value changes. It's not tied to rules. Changing rules will either have no effect if they don't win the cascade, or update the computed value if they do. The latter will typically cancel the current transition and start a new one. See https://drafts.csswg.org/css-transitions-1/#starting

or if the font size changed during a transition?

The computed value absolutizes lengths, so changing the font size will change the computed value, triggering a transition. This absolutization also implies that mixing units is no problem, they end up being compatible.

The same rules should apply to auto.

No, it's different, because auto doesn't compute as a length. auto is closer to a percentage, which also stays as a percentage in the compute value (always referring to width and height). But calc() knows how to handle a mix of lengths and percentages, that's not the case with auto.

SetTrend commented 2 years ago

auto doesn't compute as a length. auto is closer to a percentage, which also stays as a percentage in the compute value

… a percentage? 😲🤔

Hmm, may I ask: a percentage of what exactly? We may come closer to a solution if the algorithm for auto would become clearer.

SetTrend commented 2 years ago

@Loirooriol:

Regarding the other parts of your reply: You just gave the answer to all other open questions:

Transitioning from auto should just behave the same if the underlying value changes.

SebastianZ commented 2 years ago

@SetTrend wrote:

Moreover, if this thought took roots, the following (currently invalid transition) should become valid, too:

p   /* rule #1 */
{
  height: 10px;
  transition: height 2s;
}

p:hover   /* rule #2 */
{
  height: 20em;
}

As @Loirooriol wrote, this is already valid. See https://jsfiddle.net/SebastianZ/hk059ad1/. What's not working is transitioning to or from an auto value (or possible other keyword values of properties that resolve to a numeric value in the end).

@danegraphics wrote:

When we are talking about the "computed" value of auto, we are talking about the final pixel/length value of the layout with auto applied.

It seems the difference between "computed values" and "used values" still isn't clear to everyone. There's a simple example in the CSS Cascading and Inheritance specification which clarifies this:

For example, a declaration of width: auto can’t be resolved into a length without knowing the layout of the element’s ancestors, so the computed value is auto, while the used value is an absolute length, such as 100px.

So the used value is the actual numeric value that authors are referring to. And this is also the reason why @Loirooriol suggested a used() function to get that numeric value.

Sebastian

Loirooriol commented 2 years ago

a percentage of what exactly?

I don't mean that auto behaves like some specific x%. I mean that both auto and percentages compute as-is, to be resolved later during layout. Note that while calc() knows how to mix percentages and lengths, interpolating from height: 100% to height: 100px, if the percentage is cyclic, 100%*(1-t) + 100px*t will likely behave as auto during all the transition (so visually it won't be smooth, even if the computed value goes smoothly from 100% + 0px to 0% + 100px). And when the transition ends, 200px alone will not be cyclic, and there will be a sudden visual change.

So even if we allowed calc() to handle auto, in some cases it may still not look good (like already happens with percentages). This can be an argument for adding a way to transition used values instead of computed values.

SetTrend commented 2 years ago

@Loirooriol:

I think I see your point now.

Given this fiddle, if in that example the div.outer:hover rule was height: auto; and the user hovered over the red div while the outer transition is running – then how should the running outer transition behave?

Given that a transition cannot anticipate arbitrary potential future layout changes it seems impossible to find a working general solution for auto.

eoghanmurray commented 2 years ago

It's not impossible, the behaviour just needs to be written down in order for this to progress into the spec.

@Loirooriol is pointing out that allowing auto to be passed to calc enables the final (used) value to be calculated at layout time, so if that was supported the auto would be recalculated at each discreet transition step (thing requestAnimationFrame I guess?)

In the absence of such a proposal (which is elegant and general, but I don't think anyone is clamouring or has worked out the edge cases), and also because the 'virtual layout' calculations could potentially be costly, would it be possible from a spec point of view to defer the implementation details to the browser:

Is there precedence for this style of specification?

Should we write up the various approaches in separate issues? @Loirooriol a stub of each of the competing possibilities that are in your head would be very helpful!

Loirooriol commented 2 years ago

@SetTrend If auto is interpolated as a computed value, then e.g. at 50% of the transition it will be calc(5em + auto/2), so you should get the same as if div.outer has no transition and height: calc(5em + auto/2), when div.inner is as big as whatever size it has at that point during its transition. The exact behavior depends on how auto is handled in calc(), but probably this implies that the element would need to be laid out twice per frame, first with height: auto, and then with calc() replacing auto with the previous result.

With the idea to interpolation used values, all of this should be properly designed. And again, I'm not an expert in this. If we are interpolating from auto, then we just take the old used value which is an absolute length and roughly, everything seems fine. If we are interpolating to auto, then it's less clear what should happen, like what's the computed value, etc.

@eoghanmurray auto is always calculated at layout time. And again, the current interpolation model is based on computed values. If instead of interpolating auto itself, you try to resolve it first and interpolate that instead, then it's a different model that needs a proper design.

danegraphics commented 2 years ago

I want to see if I can summarize what I'm understanding from this. Please correct me if I'm wrong.

The main issue is that auto currently uses computed values instead of used/resolved values. If it were to use the used/resolved values for transitioning, then it would be able to be transitioned from and to with no issues, and it would even be able to be used in calc().

Is that correct?

If so, then I think we can assume that this is a minimal increase in computation cost for the browsers because they are essentially already doing these calculations in a roundabout way anyway.

And if that's the case, then no need to take half-measures. Just go full in and have it update on every transition step/frame.

Browsers essentially already do this if elements surrounding an auto element are changing in size and space, and those are the only situations we're really worried about.

Please correct me if I'm wrong, but assuming all this is true, then the changes to the spec that are needed are just to have browsers calculate and use a used/resolved value of auto, and then to just tell them to enable usage of auto in transitions and in calc(). No need to overcomplicate it with hacks and tricks.

eoghanmurray commented 2 years ago

the element would need to be laid out twice per frame

Is this the case for percentages within calc?

Loirooriol commented 2 years ago

@danegraphics The issue is that transitions interpolate computed values, and in height/ width a specified value of auto computes to auto which is not a <length-percentage>, and we know how to interpolate <length-percentage>s but not auto. So either we define how to interpolate auto with a <length-percentage>, or somehow add another way to transition that interpolates used values.

The computation cost will probably be there anyways no matter what we do, since changing height already implies layout at every step, yes. For a performant approach, transforms should be used instead, as explained in https://github.com/w3c/csswg-drafts/issues/626#issuecomment-841935150 and https://github.com/w3c/csswg-drafts/issues/626#issuecomment-842707084

In order to interpolate auto, the specs would need to define how a mix of auto and <length-percentage> behaves during intrinsic sizing and extrinsic sizing, clarify if things that check if the computed value is auto should check for exactly auto or also auto mixed with a <length-percentage>, etc.

@eoghanmurray Well, I guess it depends on what exactly you count. If you have cyclic percentages, the elements is laid out as auto during intrinsic sizing, and then as a definite percentage during extrinsic sizing. With a mix of auto and <length-percentage>, the details of what needs to be done will depend on how exactly it's defined.

SetTrend commented 2 years ago

I guess the calculation may become quite expensive in a deeply nested document with all nested divs heights being transitioned between auto and another value.

To determine each div's auto height, the algorithm would need to get their current heights in transition, so calc() would be required to be called on each of them.

I simulated this using padding in this example: https://jsfiddle.net/10b6whe3/

eoghanmurray commented 2 years ago

For a performant approach, transforms should be used instead

That's already possible, has a very different visual effect and IMO should not be considered as a workaround in the context of this ticket.

jimmyfrasche commented 2 years ago

What if there were a new property, say, shrink: 0% 0% and inline-shrink, etc. At its default 0% 0% it has no effect but for nonzero percentages it makes the element inert and shrinks it to that percentage of its width and/or height.

Then you can leave height alone and transition from block-shrink: 100% to 0%.

(Sorry if something like this has been brought up before and I missed it skimming this long thread)

jez9999 commented 1 year ago

Argh, I've been trying to create a pure CSS burger menu and the lack of this feature in CSS is painful. It would allow the menu to be hidden and removed from the document by setting a wrapper to and from height zero (given that you can't animate display:none). I guess it's more complicated than this, but it seems to me that browsers already calculate the value of auto for an instant transition, they already transition given an explicit value, so why not just treat auto as if the user had explicitly specified the calculated value?

yisibl commented 1 year ago

Now we can animate CSS Grid too, with it, we can finally make height 0→auto animation.

https://www.stefanjudis.com/snippets/how-to-animate-height-with-css-grid/

jez9999 commented 1 year ago

Now we can animate CSS Grid too, with it, we can finally make height 0→auto animation.

https://www.stefanjudis.com/snippets/how-to-animate-height-with-css-grid/

Annoyingly, that still doesn't work for transitioning between different calculated values of 1fr. If it's set to 1fr and the inner content changes height, the transition doesn't happen. Only when changing the explicit CSS value. Grr!

citriqa commented 1 year ago

Another benefit of auto being a computed value usable in math functions would be the ability to clamp it. I have been wanting to clamp the value of the aspect-ratio property, and short of the introduction of min- and max- variants, being able to use min, max, and clamp with the auto keyword appears to be the only solution.

Loirooriol commented 1 year ago

Now we can animate CSS Grid too

Off-topic, but it's not the 1st time that I have seen this approach with 0fr and 1fr, but minmax(0, 0fr) and minmax(0, 1fr) with overflow: hidden on the grid container are probably a better choice to ensure that the element collapses to zero.

If it's set to 1fr and the inner content changes height, the transition doesn't happen

That would require some new kind of transitions that work on used values. Right now they are based on computed values. It's the same as with height: 100% and the containing block changes from 100px to 200px. Even if the percentage will resolve to a different value, the computed value keeps being 100%, so the change will happen suddenly.

Another benefit of auto being a computed value would be the ability to clamp it.

height: auto already computes to auto. What you want is being able to use it in math functions.

chronosirius commented 1 year ago

Could the browser "imagine" the element and figure out the computed value with things like auto or fit-content, and then when asked to render this animation, it just animates between the previously computed value and the original value? For example, I have an element that could contain 2 or 3 children. So, the browser could compute the height of the element before rendering the element, which could be 200 or 300px and then, on state change, it animates between 0px (starting value) and 200 or 300px. Why would that not work?