My Navbar's Bottom Border Was There All Along, Only Transparent
The unscrolled navbar looked borderless because border-transparent still renders 1px with an invisible color. One-line fix: border-border/60.
TL;DR
The navbar's "missing" border was actually always rendered with border-transparent, reserving its pixel and preventing layout shift on scroll. The fix was one class swap to border-border/60, letting the existing transition handle everything. Lesson: keep elements present and control their color, not their visibility.
Killing time on my own site's front page, my eyes snagged on the navbar. Unscrolled, it looked like it was floating: a faint white background, blur behind it, and no line of any kind separating it from the content. Then I scrolled down, and a hairline appeared under it as the background solidified. Back to the top, the line vanished. The content suddenly looked like it was pressed right against the bottom edge of the navbar with no gap. The floating impression broke at that moment.
My first guess was obvious: the bottom border simply wasn't there in the initial state. Made sense, right? The line wasn't visible, so it must not exist. I opened the Navbar file, ready to add that "missing" border-b.
I was completely wrong. The border-b had been sitting there from the start.
A border that never went away
In the unscrolled state, the classes were border-b plus border-transparent. So that 1-pixel border was being rendered all along, still counted in the box model, still adding element space equal to its thickness [3]. Only its color was set to fully transparent, exactly what the class literally means in the Tailwind docs: border-color set to transparent [1]. My eyes were being fooled, not the layout. The space never moved; only the line disappeared from view.
That's why the navbar never "jumped" when scrolling. If the border actually appeared when scrolled and disappeared when unscrolled, the navbar height would change by 1 pixel every time it crossed the scroll threshold. Everything below it would shift along. With a transparent border, the space is reserved from the start, so the transition stays purely visual.
The fix was one line: swap border-transparent for border-border/60, the same color the scrolled state has been using all along. The rest was handled by the transition-all duration-500 already on the parent classes. The only things changing between the two states now are the border color and the background intensity, and the 500ms transition smooths it all out.
Where the /60 comes from
The /60 modifier in border-border/60 isn't just a Tailwind trick. In Tailwind v4, opacity modifiers like this are built on top of the CSS color-mix() function, which returns the result of mixing colors in a given colorspace [2]. That function has been Baseline across browsers since May 2023, so there's no half-supported behavior to worry about. The border color becomes 60 percent of the theme border color, the rest transparent, and as the transition runs, that mix is what gets recomputed every frame.
One question remains unanswered: why pick a transparent border in the first place instead of a thin one that's visible right away? The commit doesn't record the reason. My open guess is it was meant to prevent layout shift, a pattern similar to scrollbar-gutter, which reserves space for the scrollbar even when the scrollbar doesn't always show. But that's speculation. What's certain is the side effect: the line was completely invisible in the initial state, and that's what looked off.
Control the color, not the visibility
This episode made me more confident about one preference: for elements that are supposed to exist, keep them existing and play with their color or opacity instead. A border that's always rendered is calmer than one that flickers in and out, because no layout calculation can get disturbed. If the line should always be visible, adjust its color. If it genuinely must not be visible, transparent makes sense. The messy spot is the middle ground: present but invisible, exactly the state my navbar was in before.
Now my navbar has a line in both states; only the intensity differs. One class changed, the rest was handled by a transition that's been running all along.