Css transition on element creation/insertion

This is a basic question about animating using css transitions: say I want to animate the opening sidebar, or appearing popover. And I want to do this with a newly inserted element in DOM using css transitions (not css animations).

With JavaScript API I would do the following: I create an element with initial style properties set (say opacity = 0) and css transition configured, then right after the element is inserted in DOM I set the opacity style property to 1. And the element becomes visible with the transition (gradually changing opacity 0 → 1). In other virutual doms I could use this approach using element lifecycle hooks.

I don’t see this can be implemented in Elm. What would be the advice here, how such basic animation case is supposed to be solved?

1 Like

Why do you want to do it with transitions instead of animations?

I want to do this with CSS transition, not CSS animations because I want such a case to be smooth: element appearing and its opacity goes from 0 → 1, but while this It is commanded to be closed/removed, and its opacity should be smooth going down to 0 from the point where it is currently, not from 1 → 0. The same thing for re-opening the element while it’s closing. With CSS animation we need two animations fadeIn: opacity 0 → 1 and fadeOut: opacity 1 → 0. And when those operations will be started animations will be reset. With CSS transitions, we can have the smooth effect of changing opacity from a current value to a target value.

You can do it, and it’s similar to JS. Instead of creating the element when you want it to show and then triggering the property change immediately, have it always be present with 0 opacity and just change the property when you want it to be visible.

This is what I would like to avoid here, I don’t want this element present in DOM if it is not needed and should not be there, besides it can be an element with complex content, but it is just not correct, and only would work as a workaround.

For context, how would you handle removing the DOM element after the fade-out is done in JS?

Removing is done by listening to “transitionend” (or “animationend” in case of css animation) events. In Elm it can be accomplished by introducing an additional animation state.

I’ve found it out, seems I had a wrong input here, one needs to use requestAnimationFrame (with raw JS as well) to start transition after an element has been inserted.

Yes. A hack used in JS sometimes is to synchronously trigger a DOM reflow via element.offsetHeight = elment.offsetHeight:

element.opacity = 0;
element.offsetHeight = element.offsetHeight;
element.opacity = 1;

Or something like that

1 Like

If you keep the element there always, you don’t actually need any of its content to be there, just the container.

2 Likes

Well, this is a kind of an interesting and feasible approach, need to think if it is worth it. At least it can make wiring up more simple (no need for subscription or cmd for animation frame/delay). But still, it seems to be a bit dirty, that you have to keep DOM polluted with such dummy containers.

Also, (slightly off tangent but I figured why not mention it) if you want to keep the amount of CSS code to a minimum, you can configure transitions with Simple.Transition - elm-simple-animation 2.1.0 which gets compiled to CSS transitions.

1 Like

Hey !

You actually can run an animation backward if you want: animation-direction - CSS: Cascading Style Sheets | MDN (alternate is probably what you’re looking for)

oh, and last minute hack: you can have an element with opacity: 0; pointer-events: none; so that the pointer can’t see the object, it’s almost like display: none; though I don’t remember if it can catch focus with the keyboard.

Thanks for the suggestions. tabIndex could be set to -1. Seems already many rough points for a basic case. -)

I agree with @romper’s intuition that keeping these DOM elements around for the life of the app just so you can fade them in is the wrong approach.

In my photo album app, I have two different states in my model (ImgFetched and ImgLoaded). I create my <img/> element with style opacity 0, then use an onLoad event handler to know when to change the CSS to opacity 1; transition ..., so that the image fades in as soon as it’s loaded.

In your case, you’d want a requestAnimationFrame instead of onLoad, but otherwise it should work just the same.

The bookkeeping of the pair of model states for each transition isn’t great, and indeed in other parts of my app I’ve opted for using elm-animation instead to avoid that. But, with some helper functions it’s managable, and it works great.

You can see most of the code in this commit.

This topic was automatically closed 10 days after the last reply. New replies are no longer allowed.