Loading…
Loading…
This site has no header on a phone. Just a dock along the bottom edge, and the hardest decision in it was the number 4.

Open this site on a phone and there is no top navigation bar. Not hidden on scroll. It does not exist. All navigation lives in a dock along the bottom edge.
The reason is not aesthetic. It is where a thumb reaches.
Hold a phone in one hand and your thumb sweeps an arc. The comfortable part of that arc is the lower half. The top left corner, where web convention puts the logo and the menu button, is the furthest point from it.
Native apps solved this a long time ago with a bottom tab bar. The web mostly still takes the desktop header, shrinks it, and calls that responsive, because that is the easiest CSS to write.
The detail that makes the dock read as a real application rather than a floating web widget is that it spans the full viewport width: no side gutters, no corner radius, and the device safe-area padding sits inside the bar rather than below it. A bar with margins and rounded corners always looks like something drifting on top of the page.
/**
* Route tabs shown inline in the bar. MUST stay even — the orb splits
* the row in half, so an odd count leaves the bar visibly lopsided.
*/
const DOCK_SLOTS = 4;
A raised circular button sits at the centre of the bar, splitting the row into two halves. Four tabs means two per side and it balances. Five means two on one side and three on the other, and the eye catches it immediately even when nobody can say what is wrong.
Nothing enforces this constraint except that comment. No type catches it, no test goes red. Whoever adds a fifth tab six months from now will just find the bar looking slightly off. That is why the comment shouts.
This is where the problem gets interesting. A portfolio has two quite different kinds of destination.
The first is real routes: blog, algorithms, tools, puzzles. The second is homepage sections, the things you scroll to through an anchor on desktop. On a wide screen both sit in one horizontal row and nobody questions it. In a four-slot bar they do not fit.
The centre button resolves that. Tapping it blooms a full-screen sheet where the homepage sections become reachable and the explore routes are laid out as cards, each carrying its module's accent colour. The four inline slots go to the most-visited destinations; everything else is one tap behind.
First, opening the sheet starts warming the search index:
const { prime: primeSearch } = useSearch();
The search row lives inside the sheet, one more tap away. Starting the fetch when the sheet opens means the data is usually there by the time somebody types. The reader notices nothing, which is the point.
Second, the sheet traps keyboard focus. A full-screen overlay that does not confine focus lets keyboard users tab straight out of it, wander through the links still sitting on the page underneath, and lose track of where they are. This is the easiest thing to forget when building an overlay, because using a mouse never reveals it.
The dock hides itself when you scroll down and comes back when you scroll up. That sounds reasonable: give the screen back to the content.
In practice it makes navigation feel unreliable. You scroll while looking for something, decide to switch pages, and the bar is not there, so you have to scroll back up a little to summon it. Building this again I would leave it fixed and accept the fifty or so pixels. A navigation bar that is always where you left it is worth more than the space it takes.
No comments yet — be the first!