Skip to content

[css-transitions] starting an animation and a transition with equal values yields some incompatible behavior between Safari, Chrome and Firefox #8701

@graouts

Description

@graouts

If I have an element specified as follows:

div {
    width: 0;
    height: 100px;
    background-color: black;
    transition: width 250ms linear;
}

… and later on set the following styles:

div.animated {
    width: 1000px;
    animation: grow 1s forwards linear;
}

@keyframes grow {
    from { width: 0 }
    to   { width: 1000px }
}

… then what is the expected behavior with regards to transition during the lifetime of the explicit CSS Animation started when the animated class is applied? I'm observing a different behavior in each of Chrome Canary, Firefox Nightly and Safari Technology Preview. In all three browsers a CSSAnimation is yielded going from width: 0px to width: 1000px as expected. However, the behavior differs greatly for the transition:

  1. Chrome Canary (114.0.5708.0): no transition is ever started (no transitionstart event and no CSSTransition object visible when calling getAnimations() right after applying the animated class).
  2. Firefox Nightly (114.0a1 (2023-04-11)): a transition going from width: 0px to width: 1000px is started as the animated class is applied and runs for 400ms until its natural completion.
  3. Safari Technology Preview (167): same behavior as Firefox when the animated class is applied, however the transition is canceled and restarted on each frame.

While this does not yield a visible difference because the CSS Animation overrides the CSS Transition, this is still an observable difference through events and getAnimations().

Here's the complete test (sadly GitHub does not allow attaching an HTML file):

<!DOCTYPE html>
<style>

div {
    width: 0;
    height: 100px;
    background-color: black;

    transition: width 250ms linear;
}

div.animated {
    width: 1000px;
    animation: grow 1s forwards linear;
}

@keyframes grow {
    from { width: 0 }
    to   { width: 1000px }
}

</style>

<div></div>

<script>

const div = document.querySelector("div");

const currentWidth = () => getComputedStyle(div).width;

const dumpAnimations = label => {
    const animations = document.getAnimations().map(animation => {
        const keyframes = animation.effect.getKeyframes();
        return `${animation.constructor.name} from ${keyframes[0].width} to ${keyframes[1].width}`;
    });
    console.log(`${label} width is ${currentWidth()} and getAnimations() yields [${animations.join(', ')}]`);
}

const dumpTransitionEvent = event => dumpAnimations(`After ${event.type} fired`);
div.addEventListener("transitionstart", dumpTransitionEvent);
div.addEventListener("transitioncancel", dumpTransitionEvent);
div.addEventListener("transitionend", dumpTransitionEvent);

requestAnimationFrame(() => {
    div.classList.add("animated");
    dumpAnimations("After starting animations");
    requestAnimationFrame(() => dumpAnimations("One frame after starting animations"));
    setTimeout(() => dumpAnimations("100ms after starting animations"), 100);
    setTimeout(() => dumpAnimations("500ms after starting animations"), 500);
});

</script>

Cc people I know to have worked or are working on animations in the affected browsers: @flackr, @BorisChiou and @birtles.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions