Animating font-weight without the jump
A tiny detail that quietly ruins a lot of tab bars and nav menus: you make the active item bold, and because bold text is wider than regular text, every sibling shifts sideways the moment you switch tabs. If you also slide an indicator under the active item, the layout shift and the animation fight each other and the whole thing feels loose.
The active tab goes bold and wider, shoving its neighbours sideways.
The fix is to reserve the bold width up front. Stack an always-bold invisible copy of the label underneath the real one with CSS grid, so the slot is permanently as wide as the bold state. The visible label can then go bold with zero layout shift.
<span class="grid">
<!-- ghost reserves the bold width, always -->
<span aria-hidden class="col-start-1 row-start-1 font-bold invisible">
Projects
</span>
<!-- visible label goes bold only when active -->
<span class="col-start-1 row-start-1 [.active_&]:font-bold">
Projects
</span>
</span>
Both spans land in the same grid cell (col-start-1 row-start-1), so the cell sizes to the widest of the two - the bold ghost. Same trick works in plain CSS with display: grid and grid-area: 1 / 1.
Reserving the width kills the jump, but the weight still flips in a single frame. Reach for a variable font and font-weight becomes a continuous axis which you can animate from regular into bold instead of popping.
The variable font eases the weight from 400 to 700.
A variable font carries every weight in one file along a smooth wght axis, which is what makes font-weight animatable. Add a transition and the browser interpolates across it; a static font has nothing to land on in between, so it just jumps.
.tab {
font-weight: 400;
transition: font-weight 0.3s ease;
}
.tab[aria-selected="true"] {
font-weight: 700;
}
Keep the reserved-width ghost underneath and you get both at once: no layout shift, and a weight that glides.