Csswg-drafts: [css-transitions] Transition to height (or width) "auto"

Created on 20 Oct 2016  路  37Comments  路  Source: w3c/csswg-drafts

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鈥檓 sure there must be discussion about this in the old mailing list, but I鈥檇 love to be privy to it here.

css-transitions-1

Most helpful comment

I caught up with @dbaron about this recently and it seems a likely way forward is to make 'auto' into a computed value. As well as enabling animation with auto, that would also make it possible to write expressions like calc(auto + 10px). While that might not be trivial to implement, since there is interest from authors' and, I believe, browser vendors, it seems promising.

(One way to push this forward would be to submit a patch to one of the open-source browsers for this. Once you've proven the technical feasibility of this, it's easier to argue for it to be added to the spec.)

All 37 comments

Adding here what I replied to @keithjgrant via Twitter:

In order to interpolate to/from an auto or other keyword value, you need to have a way of describing the intermediary state. For lengths, intermediary states can usually be described via a calc() function. 10% of the transition from 50px to 20em is calc(0.9*50px + 0.1*20em). So the most generic approach to supporting transitions with keywords would be to allow the keywords to be used in calc(), with a real-time substitution of the current computed value that the keyword would create.

Sure, there are edge cases where the performance would inevitably be horrible (e.g., if you are transitioning to/from auto at the same time you are also changing things that would cause the current computed value of auto to change), but that shouldn't be reason to prevent its use in more sensible cases.

@keithjgrant yes, this is a real problem.

For the moment, we set up transitions on max-height value (using magic numbers for values, max-height = enough_and_pray_the_content_is_not_that_tall), and if you want to do it including accessibility pov, you have to transition on visibility (as display is not possible, cf this accordion https://a11y.nicolas-hoffmann.net/accordion/?animated=1 ) with a delay... really complicated for something that should be simple. :)

Looking around the web, you can easily see that this is a constant problem for developers. Velocity.js even notes this specific missing feature in its first paragraph of why it exists (https://fabric.io/blog/introducing-the-velocityreact-library). I can probably give a ton of references (on request) of developers rendering an element, measuring it, setting it's height to 0 then animating to that specific height. Even JQueryUI does a similar measurement technique just to get this to work and it's been around for almost a decade now.

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

Do we need to have more people come here and upvote this bug? Do we need to email a specific individual? Let us know so we can let you know what we need most.

I too am curious what we (the web programming community in general) can do to petition a change in the spec... I've got a few issues I know I could get quite a few people backing.

I caught up with @dbaron about this recently and it seems a likely way forward is to make 'auto' into a computed value. As well as enabling animation with auto, that would also make it possible to write expressions like calc(auto + 10px). While that might not be trivial to implement, since there is interest from authors' and, I believe, browser vendors, it seems promising.

(One way to push this forward would be to submit a patch to one of the open-source browsers for this. Once you've proven the technical feasibility of this, it's easier to argue for it to be added to the spec.)

auto is already a computed value; the thing that needs to happen is adding support for auto to calc().

Awesome I'll start looking into it using Firefox since I think theirs would be the easiest source code to get a hold of. That said, it may take me a while due to lack of cpu resources (my computer is a 2 core 2.4ghz processor... it's going to take a while to build).

Thank you very much for bringing this up. We currently work around this by reading out an elements scrollHeight and transitioning to that height, only to revert the element height to auto on transitionend. So making this a platform feature would be fantastic.

It has been suggested that we use max-height: max-content.

But trying to get the browsers to implement either has been very difficult, as the CSS animations are typically done between 2 known values, which is why animation usually needs to be done with something like max-height: 500em.

As an aside (and for some of the background on this), I've been trying to get browsers to support auto-height <iframes> and <textarea>s, which will work in pretty much the same way:

https://github.com/craigfrancis/iframe-height

https://discourse.wicg.io/t/feature-request-animating-max-height-height-based-on-content/1403

+1. Not being able to transition on height: auto and display: <anything!> (You can't even do a transition-delay on display) has always been a big pain.

Just FYI I'm currently out of the country and I'm also checking with my legal department to see if this is something I'm allowed to do due to where I work (non-compete and helping competitor issues). I'll be back in town on the 20th.

@nilssolanki That's the same trick we're using and it's just annoying.

@Jakobud I would say animating display is a bit out of the bounds of this request and may also have a few edge cases that would be interesting (animating inline to block?).

My legal department has come back to me informing me that I'm unable to currently work on this request due to non-compete legal stuff. That said, I'll have to (frustratingly) recuse myself of any code writing for this feature.

Just to note, I also asked a google groups question here if anyone is interested in taking this up. It should give a basic guide to how I was planning on tackling the problem.

https://groups.google.com/forum/#!searchin/mozilla.dev.tech.layout/auto%7Csort:relevance/mozilla.dev.tech.layout/fFuJqwXvu2I/6_mt7HmhDAAJ

Just want to make sure this is still happening.

This is actually rather important because, yes, we can precalculate a value for height and other properties using javascript and things like document.getElementById(elementID).scrollHeight+'px' , but sometimes we need the property to have an auto value after the animation/transition so that we can make changes inside and around the element that the element will respond to appropriately.

For example, I have an element that transitions from a height of 0 to a height of 'auto'. After the transition is completed I want the height of the element to be able to adjust correctly to the changing elements inside of it without me having to recalculate it myself.

So if it really is just adding auto compatibility to the calc() function, as @dbaron has mentioned, is someone working on that, and if not, how would one do so?

To my knowledge no one has picked up this work and I'm still barred due to legal constraints. But if you download the source code and read the conversation here:
https://groups.google.com/forum/#!searchin/mozilla.dev.tech.layout/auto%7Csort:relevance/mozilla.dev.tech.layout/fFuJqwXvu2I/6_mt7HmhDAAJ

It should give you a few locations to pinpoint where you would need to make the changes you need. Not sure if those are all of them but it should give you a starting point for learning the code base.

Good luck, I hope you do take this up because it would be an amazing addition!

I'd have to review to make sure that 'auto' doesn't have any special behaviors that make it incompatible with explicit lengths in some situations. That is, any place where the layout system does special things if the width/height is "auto", such that replacing the "auto" with its equivalent absolute length would give a different result.

I can't remember the source, but it was recommended we use height: max-content rather than auto... this might have started from you TJ.

Where it would be nice if we could use this keyword for iframe's and textarea's as well.

@k2snowman69 I would love to take this on and get it done. My question is what all would I need to change? I understand that there are the specification pages that explain how the transitions should be interpolated, and that those should be changed if this is added, but is there also some actual coded function or set of functions that would need to be modified? If so, where can I find them?

@tabatkins Do you know of any situations where that would be the case? (that auto acts differently than it's explicitly stated px size?)

Linked to this discussion in an answer at Stackoverflow where I point out that transition to height: max-content does seem to work in Chrome: https://stackoverflow.com/a/45203565/4200039~~ nevermind, deleted the answer as I think I got confused somehow - doesn't seem to work

How can I transition height: 0; to height: auto; using CSS? is currently the top-voted question in the css-transitions tag, with nearly 5 times as many votes as the third-highest.

Also, what's the story with bugzilla these days as far as CSS? There's this bug - pointed here.

While height is easy to get to the calculated auto through max-content, it would be best if this were to work for multiple properties such as width (there is no setting comparable to auto) and others. It is impossible to use javascript to get width to work properly without manually doing the math to remove the L&R margins, padding, and border from the 100% calculation, and other properties have similar setting problems.

Using the pre-calculated auto value as the target setting for each property that has an 'auto' option, while actually setting it to 'auto', would be the best method from what I can see.

PS: The data from Stackoverflow suggest that this is the most requested feature for the next CSS update. Using Stackoverflow's highly voted issues would probably be a good place to look for other features that might be good to include in the next version.

I used to really really want this feature, but over the years have found myself being content with transitioning a transform in many cases, while having a parent element set in inaccessible ways...

.parent {
  pointer-events: none;
  visibility: none;
  overflow: hidden;
}
.element {
  pointer-events: auto;
  visibility: visible;
  transition: transform ease .375s;
  will-change: transform;
}
.transformed .element {
  transform: translateY(-100%);
}

Here, the -100% seamlessly takes care of the auto height and transitions a texture over possibly invaliding layout during a height transition. Not saying this is the silver bullet for the issue, but offering what I've found to be a more performant option for most cases. And furthermore, if we did get the ability to transition to/from auto, I'd rarely use it over this approach. Though, this obviously doesn't handle the case where you'd want flow content to move along with the "height" transition, which again, is not as performant.

@jonjohnjohnson do you have a codepen/jsfiddle example of this anywhere and if not would you mind posting an example here? Many thanks

@cohsteve Quick -> https://jsfiddle.net/rwozw4bs/

Also, read up on FLIP animation methodology to see how you *could approach animating transforms while simulating the movement of flow content. https://aerotwist.com/blog/flip-your-animations/

@jonjohnjohnson A transform effect works for absolutely positioned elements. But if the element is statically positioned, it still takes up space in document flow when scaled down to height 0.

Transitioning max-height was also mentioned above, but this too has a problem: the timing function is unreliable, since part of the transition will continue well after the max-height has reached the actual height of the element.

@keithjgrant correct. I find the gains from transforming a texture and not invalidating layout worthwhile, as opposed to the *few times I find myself wanting to animate within a flow.

Just making sure that this project hasn't been abandoned.

@dbaron, I see you are also the one assigned to the Mozilla ticket as well? (https://bugzilla.mozilla.org/show_bug.cgi?id=571344)

(I don't mean to be so pokey about this. I just keep running into designs where having this would immediately make the desired-but-impossible possible. So I hope that a fix for this bug will come soon.)

How is this, after so many years, still not solved?

Bump

I've written a polyfill which converts the max-height + overflow:hidden hack-around for this issue into a more precise height transition. https://github.com/eoghanmurray/height-transition-polyfill

The basic idea is to measure the height at the start of the transition and assign it via style attribute. For the reverse transition from 0px to auto, because of the overflow:hidden, the scrollHeight attribute gives a good approximation of a target height for transitioning. (all these extras are removed after transition completes).

Transitioning from/to auto doesn't appear to cause any performance or other difficulties for the overflow:hidden case, as the internal element layout doesn't need to be recalculated (so e.g. height can't affect width).

I believe this special case (transitioning width/height with overflow:hidden to/from auto) represents 95% of the usecases [citation needed!], and should be a lot simpler to implement/standardize vs. the more general to/from auto/max-content. Is there an argument to be made for focusing on this first? (i.e. wish this case was standardized 10 years ago!)

I'd like to add that transitions/animations on auto valued properties should also be triggered when content changes:


<!DOCTYPE html>
<html>

<head>
  <meta charset="UTF-8">
  <title>Replaced content transition</title>

  <style type="text/css">
    div
    {
      border: 2px solid #caa;
      background-color: antiquewhite;
      padding: 1em;
      margin: 2em auto;
      width: 80%;

      transition: height 1s;
    }
  </style>
</head>

<body onload="setTimeout(() => document.getElementById('replaceMe').src='b.png', 2000)">
  <div><img id="replaceMe" alt="" src="a.png" /></div>
</body>

</html>

@SetTrend, the proposal sounds good, but I think it is too complicated. Think ... when having auto height, from what height expected to began the transition when loaded page of whapper containing only text? Form 0 or should transition be ignored in first paint? Then when screen width changed and text wrapps to more or less lines expanding or collapsing its wrapper size - would you expect transition to be applied for wrapper height?
Maybe transition should apply when fixed height size changes to "auto", and when opposite then on initial paint to ignore the transition, otherwise would look weird like in my bottom link.

See this Chrome bug https://lab.laukstein.com/bug/input having since beginning of CSS3 transitions and imagine how wrong it can get if the spec proposal gets wrong, or browsers gets it wrong.

@SetTrend Interpolations work on the computed value. If you interpolate from auto to auto then it won't be smooth. This already happens if you have height: 100%; transition: height 1s and you change the height of the containing block. Then the used value of height: 100% changes, but it's a sudden change since both the 100% starting point and the 100% end point are updated.

@laukstein / @Loirooriol: Good thoughts.

First of all, I would suggest to have transitions and animations always be based on the computed* device pixels value, regardless of the CSS length currently being applicable to an element. Doing so, we get an abstraction layer between how a width or height is declared and what it really is on the device.

Then, in the event of (a) content changing, (b) styles getting dynamically applied or (c) transitions/animations being triggered, I would - figuratively speaking - draw the page having transitions/animations disabled. Then I'd get the computed device pixels values for all elements properties, and store those "target" device pixels values as shadow properties along with those elements. Next, I would re-enable transitions/animations and have them animate all elements whose current (probably in-transition) computed device pixels value deviate from the newly computed "target" device pixels value accordingly.

I once wrote a JavaScript function that works exactly like this (using hidden shadow elements, so running transitions on the target elements won't get interrupted) and, from my observation, it works like a charm so far.

I'm not sure, though, if it was necessary to re-evaluate descendant elements having width/height transitions applied while an anchestor element is being in transition, or to just have descendants strictly animate to their "target" size once it has been computed, regardless of its anchestor's in-transition dimensions.

@laukstein : Given my above explanation I would suggest to use the computed "target" device pixels value as an immediate starting point for any initial transition/animation.

* I wrote about "computed values" but I'm actually referring to "used values".

@SetTrend, let's say your transition wrapper contains a text and now is added an image into it expanding its height with transition. Because now the wrapper size and its content size differs till transition end, would you expect always to flicker it with scrollbar till transition end? - know that having scrollbar will mean less width and some text wrapped to more lines, while when transition ended you would expect no more scrollbar and text wrapped normally - no extra line wrapping due to scrollbar - that saying it will flicker delivering bad UX. The workaround would be to add overflow: hidden for the transition wrapper but that sound already bad and as a limitation imagining to apply it to all places using this type of transition.

@laukstein : Yes, absolutely. That's the intrinsic nature of a transition: Intermediate state. It's up to the web page designer to circumvent and handle such condition in a sensitive manner.

Another year, another checkup.

I'm surprised that this bug still hasn't been fixed or even committed to. At this point pretty much everyone agrees that transitioning to auto is a necessary feature. Until this gets fixed, we're stuck with a bunch of ugly workarounds, each of which have a catch.

The question now is what will it take to get it implemented and who is in charge of taking those steps?

Heck, if it's something I can do, I'll do it. But I'm here because I don't know where to start and I'm assuming someone here does.

So, what's it gonna take?

Hi, what I'm about to mention isn't exactly a height: auto solution but it doesn't rely on max-height being set to a exceptionally high value which will allow an element to expand to any size, instead it relies on max-height: 100% through a flex element.

While I was working on a component library we had the need for an "Expander" component and I managed to build something that expands to "100% height" of the element but with max-height: 100%;.

I'm wondering is this a bug that may be "fixed" in browsers in the future, or is it somewhat safe to assume that since this is working due to the flex specifications it's safe to use?

I believe it works by the fact that display: flex; elements are aware of their own size and as such can adjust to their "max height". Somehow it only works if it's not a direct element child of the flex container though.

https://codepen.io/jchiem/pen/vYGXxbq

@jchiem that looks like a great solution, and you should also post it here:
https://stackoverflow.com/questions/3508605/how-can-i-transition-height-0-to-height-auto-using-css
It's certainly the best CSS solution I've seen.
Incidentally, the nested child is likely needed as the first child (.expander__container2 in the non-working example) is rendered as a flex-item, so it's dimensions are being controlled by the flexbox model, rather than preserving intrinsic dimensions like the .expander__content element does.
Of course we still need the spec updated!

Was this page helpful?
0 / 5 - 0 ratings