Why I Rebuilt My Portfolio Navigation From Scratch (Twice)

I thought my portfolio nav was smart. Then I used it on an actual phone. This is what broke, what I rebuilt, and what I will never ship again without testing.
Why I Rebuilt My Portfolio Navigation From Scratch (Twice)
Photo by Ales Nesetril / Unsplash

Version 1: The very clever nav that nobody could use

I love overbuilding navigation. It feels important. It sits on every page, so it is very tempting to treat it like a micro SaaS instead of six links and a logo.

My last portfolio redesign was no exception. I sketched a beautiful desktop-first layout. Centered logo. Split nav. Animated underline. Smooth scroll to sections. Keyboard shortcuts. The usual developer candy.

On a 27-inch monitor it felt sharp. Confident. Like: yes, this belongs to a person who builds web experiences for a living.

Then I opened it on my phone.

Instant regret.

The original UX fantasy

The first version of the nav was built around one idea: the portfolio is a single-page experience and the nav is a timeline, not just a menu. Each item snapped to a section. The active item highlighted based on scroll position. I wrapped it all in a sticky, semi-transparent bar across the top.

Desktop layout:

  • Logo dead center.
  • Links split left and right of the logo.
  • Animated underline that slid between items on hover.
  • Subtle blur background using backdrop-filter.

On mouse hover it felt alive. I wired it with IntersectionObserver for section highlighting. Smooth scroll on click. Mild easing. Nothing too wild.

On desktop with a trackpad, this felt great. On mobile, the same design turned into a weird little puzzle.

Problem 1: Split nav + thumbs = bad combo

The split navigation around the logo was my first mistake. It looks nice in Dribbble shots. In actual thumb ergonomics it is trash.

On mobile I scaled it down into a horizontal scrollable bar. Left links were reachable with the left thumb. Right links, not so much. I found myself shifting how I held the phone just to hit “Contact.” That should have been my first red flag.

I tried to save it with padding and larger touch targets. It still felt off. The distance between items meant more reach and more micro-movements with the thumb. It was tiring in a way that is hard to see in Figma but very easy to feel on a train.

If a nav makes you adjust your grip, it failed. I had built a nav for screenshots, not for hands.

Problem 2: Sticky headers plus hero sections

I like sticky headers. I also like tall hero sections with strong visuals. On small devices those two preferences fight each other.

The sticky nav sat over a full-height hero. The hero had a headline, subcopy, and a big CTA. On mobile, the sticky bar covered just enough of the top so that the headline wrapped badly on some viewports.

Worse, when you scrolled down, the content felt “trapped” under the header. The hero already took almost the full screen. The sticky nav stole another chunk of vertical space. The result felt cramped and busy.

I had optimized for constant nav visibility. On mobile that translated to constant nav presence. It never shut up. There was no breathing room.

Problem 3: Smooth scroll lag

I wired the nav to smoothly scroll to each section. It looked great in Chrome dev tools. On my actual older Android test phone it felt… sticky.

The scroll animation plus the IntersectionObserver logic plus some other scroll-based effects combined into noticeable lag. A tap on a nav item did not feel instant. You tapped, waited a fraction, then the animation started.

I could see the browser negotiating layout, painting, and then animating. This is the kind of thing you never notice on a new MacBook, but it shows up quickly on a real mid-range phone with a bunch of apps in the background.

Navigation has to feel snappy. Even 150 ms of perceived hesitation makes the whole site feel heavier. I had traded perceived performance for fancy motion.

Problem 4: Hover thinking on a touch screen

I treated hover as a fundamental part of the interaction. The animated underline followed your cursor when you hovered across items. It helped you understand which section you were about to hit.

On touch you get none of that.

My first mobile pass just disabled the hover-driven underline and only showed the selected state. So the first tap felt blind. You do not see anything until after the nav has already moved the page.

On desktop the hover state is a preview. On mobile it simply does not exist. That is not news, but I ignored the consequence: my whole mental model for this navigation was built around a state that mobile users never see.

Problem 5: Scroll-based highlighting and short viewports

The IntersectionObserver logic felt slick when sections were tall and distinct. Then I tested on smaller phones and landscape orientation.

Some sections never technically entered the viewport enough to trigger the highlight threshold in a satisfying way. Others flickered between two states because my thresholds were tuned to a much taller viewport.

So the active nav item jumped around. You would scroll a tiny bit and the highlight would pop to the next item, then back. The net effect was that the nav constantly changed while you were reading.

Navigation should be calm. Mine was twitchy.

Rebuild 1: Accepting that mobile is the main use case

After a full weekend of trying to patch these problems, I gave up and started over. I made one simple decision: mobile would be the primary design, not the resize target.

That changed everything.

The new rules I gave myself:

  • The nav must be reachable with one thumb, on both hands.
  • Nav elements must not permanently steal vertical space on small screens.
  • Scroll behavior must feel instant, not pretty.
  • The nav must communicate state without hover.

I killed the split layout. I killed the full-time sticky header on mobile. I killed the fancy underline that tried to be too clever.

Enter the bottom sheet experiment

I moved the main navigation trigger to the bottom right corner. Big circular button. Easy to hit with your thumb. Think floating action button, but cleaner.

When tapped, it opened a bottom sheet: a simple vertical list of the main sections. Icons next to labels. Large touch targets. This covered about 60% of the screen height, so you still had a sense of where you were behind it.

This solved a few things immediately.

  • The main content owned the screen. The nav stayed out of the way until you needed it.
  • All items were reachable with minimal thumb movement.
  • The mental model was simple: tap button, choose section, jump.

I wired it to jump, not smooth scroll, on narrow viewports. Instant. No easing. On larger screens it still used smooth scroll, but with shorter duration.

This version felt fast. It also looked a bit like every mobile app pattern I had seen in the last five years. Safe, but generic.

Where rebuild 1 failed

The bottom sheet approach did its job. It fixed the main mobile pain points. But new problems showed up.

First problem: discoverability. On desktop it was obvious what was happening. On mobile, the floating button did not immediately read as “menu” to everyone. One tester thought it was a contact button. Another thought it was a scroll-to-top button.

Second problem: context loss. When the sheet opened, you lost the visual connection between the nav item and the corresponding section. Sure, the labels helped, but the spatial relationship vanished. It felt detached from the page instead of being part of it.

Third problem: transition cost. Opening and closing the sheet was one extra step. Tap to open. Tap an item. Land on section. It did not feel heavy, but it also did not feel direct. There was a layer between you and what you wanted.

The nav had gone from noisy and clever to quiet and slightly sluggish. Functionally fine. Emotionally unsatisfying.

Rebuild 2: A boring header that finally works

I decided to rebuild it again. This time I gave myself a different rule: I would not invent a new pattern. I would steal the boring pattern that most good websites already use, then tune the details.

The final version that shipped is not shocking:

  • Top header with logo on the left, nav on the right for desktop.
  • Same header collapses into a classic menu button on mobile.
  • The header is only sticky after you scroll past the hero.
  • On mobile the sticky state uses a thinner variant to take less vertical space.

The mobile menu is a full-height overlay with a vertical list of links. Big targets. Simple animation. Clear close icon in the top right. No blur. No fancy underline. Just current-state highlighting and a subtle background tint.

For scrolling, I dropped smooth scroll on mobile entirely for section jumps. You tap. It jumps. The only animation is a slight fade-in on the new section content to hint that something changed. It feels direct.

IntersectionObserver still powers the active state in the header, but the thresholds are tuned separately for desktop and mobile using a quick viewport heuristic. On shorter viewports, the highlight changes later, when the section is properly in view instead of as soon as it touches the top.

The UX principles that survived

Rebuilding the nav twice taught me a few rules that I will keep for future projects.

1. Design for hands, not cursors

I used to think of viewports as pixels. Now I think in thumbs. Can you hit every important action without stretching your grip or changing hands? If not, change the layout.

I sketch navs on paper now, with a crude phone outline and a dot where the thumb usually sits. Low tech. Very effective.

2. Stickiness is a privilege, not a default

Sticky headers look clean in static mockups. On small screens they constantly tax vertical space. I now only make headers sticky after some scroll and I usually shrink them in that state.

If a sticky element is always visible, it has to earn that attention. The first version of my nav never earned it.

3. Motion is expensive on real devices

I do not trust animations that feel fine in Chrome dev tools anymore. Every motion is guilty until proven innocent on a slower phone.

The rule I use now: if an animation is part of navigation, it needs to be nearly instant. Decorative animations can be longer, but anything between user intent and new state has to feel snappy.

4. Hover states are sugar, not structure

If an interaction depends heavily on hover to communicate what is going on, it is not finished. Hover is nice, but the core UX has to work without it.

My first nav literally assumed hover as a teaching mechanism. That is fine for desktop-first enterprise dashboards. It is lazy for a public website that most people will visit on mobile.

5. Don’t outsmart common patterns

I tried to be clever with my navigation. It looked unique but it failed basic expectations.

Most visitors do not care about your custom menu concept. They want to see your work, find your about page, and contact you if they like what they see. A standard header with a clean menu solves this quickly.

I still care about visual identity. I just express it in typography, motion, and content, not in bending navigation into a new shape.

What I ship faster next time

Rebuilding my portfolio nav from scratch twice felt silly at first. But it forced me to run my ideas against real devices and real hands instead of imaginary users living inside Figma.

Next project, I will prototype the mobile navigation first. I will test it on a mid-range phone, on a slow network, with one hand, probably while walking around the living room. If it feels annoying there, no amount of clever CSS on desktop can save it.

Desktop navs are easy to overdesign. Mobile navs are honest. They tell you quickly if your ego is driving the layout. Mine definitely was. Twice.

This round, the nav that shipped is not the prettiest version I designed. It is just the one that finally survived contact with my phone.

Subscribe to my newsletter

Subscribe to my newsletter to get the latest updates and news

Member discussion