Enter with @starting-style

Animate entry with @starting-style, and translate by percent.

From emil-design-eng (github.com/emilkowalski/skills ↗).

Add items

Click Add a few times, then switch the left pane.

No entry animationBad
    list.prepend(li)
    @starting-styleGood
      list.prepend(li)
      .item {
        transition: opacity 250ms var(--ease-out),
                    transform 250ms var(--ease-out);
      
        @starting-style {
          opacity: 0;
          transform: translateY(-100%);
        }
      }
      
      list.prepend(item);

      Drawer: 88px vs 100%

      Open the drawers, then drag Lines.

      translateY(88px)Bad
      closed
      translateY(100%)Good
      closed
      .drawer {
        transition: transform 300ms cubic-bezier(0.32, 0.72, 0, 1);
        @starting-style { transform: translateY(100%); }
      }
      .drawer[data-closing] {
        transform: translateY(100%);
        transition-duration: 200ms;
      }

      Why it matters, pros and cons

      Why it matters

      @starting-style gives a new node a start state; 100% always clears it.

      Pros

      • No mounted flag, no double rAF.
      • Still a transition, so it stays interruptible.
      • Old browsers just skip the animation.

      Cons

      • Needs Chrome 117, Safari 17.5, Firefox 129.
      • Entry only; exit still needs a closing state.
      • Reused DOM nodes will not replay it.