# Sticky headers and launch-ready pages

> Pick a header behaviour that isn't the generated default, never hijack the scroll, and ship public pages that load fast and preview well when shared.

Module: Layout and pages · Level: intermediate · 8 min · https://school.agents.org.in/design/layout/sticky-and-launch

Scroll the article in this frame with the default header. Then try the other three.

*[Interactive demo: Four headers. The first is on nearly every generated landing page.]*

The first one, 70% white, 12px blur, no edge, pinned on every page, has become a tell. Nothing about it is broken; it is simply what every generated site does.

## Pick a header on purpose

A sticky header (A top bar that stays pinned while the page scrolls under it (position: sticky). Useful, overused, and often given a blur that has become a tell) stays pinned while the page scrolls. The skill offers four choices:

- **Solid with a border.** The page color plus a 1px border. Calm, cheap to render, nothing to notice.
- **Hide on scroll down, show on scroll up.** It gets out of the way while you read and comes back the moment you head up toward it.
- **Not sticky.** For long reading (articles, docs), the nav can simply scroll away. The calmest option.
- **Blur, but tuned.** If you really want glass: about 6px of blur, your own page color at around 85%, a 1px bottom border, and only on marketing pages.

## Never hijack the scroll

Scroll hijacking (When a page intercepts your scroll and does something else: snapping between sections, playing an animation, or slowing down. It makes the scroll feel broken) is a page that takes your scroll and does something else with it: snaps between sections, slows down, locks until an animation finishes, or moves the background at a different speed. The same gesture behaves differently from every other page, so the scroll feels broken.

Scroll snapping is right in a few contained places: a horizontal carousel, a gallery of explicit slides, a step-by-step onboarding. **Snap the contained scroller, never the page.**

Scroll-driven animation can be fine when it follows your scroll one-to-one: a reading progress bar, a gentle parallax no slower than about 0.7× scroll speed. Wrong whenever it changes how scrolling behaves, slows it down, or plays differently going up than down.

## Marketing pages: a bigger budget, still small

A visitor sees a landing page once, not a hundred times a day, so it can afford a little more expression. Emil Kowalski's checklist keeps it honest:

- **Motion maps to input.** No scroll-triggered fade-ups, no auto-advancing carousels. If the visitor didn't cause it, cut it.
- **Intro animations play once per session**, gated with `sessionStorage` (not `localStorage`, which would kill them forever).
- **Readable on the first frame.** No preloader; the headline readable on first paint. taste-skill's capture of 99 award sites found 60 opening on a loading screen and a third still unreadable 4.5 seconds in. Design marks were the same either way; only usability dropped.
- **Pre-render content pages** and preload the fonts and hero image, so nothing shifts on load.
- **Content stays in the DOM.** Nav submenus are visually hidden, not mounted on hover, so crawlers and screen readers see them.
- **CTAs know who's looking**: "Get started" logged out, "Open app" logged in.
- **Docs are for copying**: a copy button on every snippet and every page available as markdown.

*("Marketing tolerates more motion" gets read as "marketing wants more motion". The extra is one first-run hero moment, not every section animating in.)*

## What a link looks like when it's shared

Launch day *is* people pasting your link into chats. Flip the switches to build the preview a chat app shows.

*[Interactive demo: Bare URL, framework default title, a broken image from localhost, then a real preview.]*

The preview comes from Open Graph tags (Meta tags (og:title, og:description, og:image) that chat apps and social sites read to build the preview card when someone pastes your link). The rules:

- **A real title on every public route.** One template in the root layout (`%s · Product`), a per-route title, and generated titles for dynamic pages. Take the words from the page's own `h1`; never ship the framework's default.
- **A description** from copy that already exists, like the hero's supporting line.
- **An image at least 1200×630**, with the large-image card type.
- **`metadataBase` set to the production domain.** Without it, relative image URLs resolve to localhost and the preview breaks in production.
- **Crawl rules.** A leftover staging `Disallow: /` or site-wide noindex (Instructions that tell search engines not to list a page or site. Left over from a staging site, they quietly hide your launch from search) quietly hides the whole site from search. That's a launch blocker.
- **Icons**: your own favicon, an SVG icon and an `apple-touch-icon`.
- **The paying path works end to end**: landing, button, signup or checkout, first screen. Every link resolves and the price on the page matches the price at checkout.

Then paste the production URL into two chat apps and look.

**Launch pass (paste into your agent):**

```text
Pre-launch pass on our public pages:
- Header: solid page color with a 1px border (or hide on scroll down / show on up). No default 12px/70% blur.
- No scroll hijacking, no scroll-triggered fade-ups, no auto-carousels; snap only contained carousels.
- No preloader; h1 readable on first paint; intro animation gated by sessionStorage; fonts and hero image preloaded; content pages statically generated.
- Metadata: title template + per-route titles taken from each page's h1, descriptions from existing copy, a 1200×630 OG image, metadataBase = production origin.
- Check robots/sitemap for staging leftovers, add favicon + SVG icon + apple-touch-icon, and walk landing → CTA → signup end to end. List anything you can't fix (missing images, price mismatches) for me.
```

**Check yourself:** Your OG image works locally but every shared link in production shows a broken image. Most likely cause?

- [ ] The image is too large
- [x] No metadataBase, so the relative image URL resolves to localhost
- [ ] Chat apps don't support OG images
- [ ] The page uses client components

*Why:* Relative metadata URLs need a base. Without the production origin set, they resolve to the development host.

## In the skill

- https://school.agents.org.in/skill/layout/sticky-and-scroll-tells.md
- https://school.agents.org.in/skill/layout/marketing-surface-rules.md
- https://school.agents.org.in/skill/layout/share-and-crawl-metadata.md
