Transform
A browser builds a frame in stages. It works out where everything sits, paints the pixels, then hands the layers to the compositor to put on screen. Which property you animate decides how many of those stages it has to run, and it runs them again for every frame of the transition.
Transform only touches that last stage. The element has already been measured and painted, and moving it is the compositor rearranging work it has in hand. Opacity is the other property that gets this treatment, for the same reason. Width, height, top, left, margin and padding all send it back to the first stage, sixty times a second, on the same thread as your JavaScript.
If a movement can be written as a translate or a scale, write it that way. Anything else asks the browser to redo the page on every frame.
Height, 0 to 36px. The paragraph is pushed the whole way.
translateY over the top. The paragraph never moves.
Point at either one to play it
The cost is not only frame rate. Animating height means everything after the panel gets a new position on every frame, so the text under it slides rather than sitting still, and anything the person was reading moves while they read it. The transform version leaves the rest of the document alone because it never asks for a new layout.
What this looks like when it goes wrong
Rarely like a broken animation. On the machine it was built on it looks fine, because that machine has frames to spare. It shows up on a mid range phone, on a page that is already rendering a list, as motion that arrives in three steps instead of thirty, and by then it reads as the app being slow rather than as one transition being wrong.
When you need the size to change
Sometimes the layout genuinely has to move, and a scale is a lie. Text inside a scaled box gets stretched with it. Two ways out. Reserve the space and slide the content into it, which is the right hand demo above. Or accept the layout pass, keep it short, and keep it off any frame that is already doing work.
Where a scale does work is anything without text in it that has to grow from a known ratio, a button press or an icon. A press is a scale to 0.97 rather than a smaller padding, and it costs nothing.
Translate rather than top and left
The same movement written as top or left is the version most people reach for first, because it is the one the box model suggests. It produces a new layout on every frame for a result that is visually identical, and it cannot be interrupted cleanly, because the element is genuinely somewhere else rather than being drawn somewhere else.
will-change is not free
Promoting an element with will-change gives the compositor its own layer, which is what makes a transform cheap. A layer also costs memory, and a page that promotes every card has spent that memory everywhere and gained it nowhere.
Put it on the element that actually moves, and only while it is likely to move. Left on permanently it is a hint the browser has to keep honoring for something that is not happening.