Sticky and scroll tells
Background-blur on sticky sections is an AI tell. Scroll hijacking confuses users. Native scroll usually wins.
Raw markdown On GitHubreferences/layout/sticky-and-scroll-tells.md
Two of the most overused (and easiest-to-misuse) page-level patterns: blurred sticky nav, and scroll hijacking. Both signal "AI-generated landing page" when applied generically.
Blurred sticky nav — the AI tell
/* The pattern that gives it away */
.nav {
position: sticky;
top: 0;
background: rgba(255, 255, 255, 0.7);
backdrop-filter: blur(12px);
}This pattern is fine in moderation and with context-specific tuning. But the default-AI-output version is:
- 12px blur (too strong).
- 70% white background (too opaque).
- Universal application (sticks on every page, even pages where it shouldn't).
- No border-bottom for separation (so scrolled content bleeds under the nav awkwardly).
The result: every AI-generated landing page in 2025–2026 has the same blurred nav. It's become a tell.
What to do instead
Pick one of these:
A. Solid sticky with subtle separation
.nav {
position: sticky;
top: 0;
background: var(--bg-base);
border-bottom: 1px solid var(--border-default);
}Cleaner, faster (no GPU blur), no AI smell.
B. Hide on scroll-down, show on scroll-up
let lastY = 0;
window.addEventListener('scroll', () => {
const y = window.scrollY;
document.querySelector('.nav').style.transform =
y > lastY && y > 100 ? 'translateY(-100%)' : 'translateY(0)';
lastY = y;
});The nav appears when the user wants it (scrolling up, presumably to navigate) and stays out of the way otherwise.
C. No sticky at all
For long-form content (articles, docs), the nav can simply scroll off-screen. The user scrolls back to top when they want nav. This is the calmest option.
D. Blur — but tuned
If you genuinely want the blur effect, tune it:
backdrop-filter: blur(6px)(not 12px).background: rgba(var(--bg-base-rgb), 0.85)(matches your palette, not pure white).- Add
border-bottom: 1px solid var(--border-default)for clean separation. - Apply only on marketing pages, not in-product.
Scroll hijacking — avoid
"Scroll hijacking" = the page intercepts the user's scroll input and does something other than scroll (snap to sections, trigger animations, change layout). Examples:
scroll-snap-typeon a long page where the user wants to scroll freely.- Parallax that decouples scroll speed from visual movement.
- Section-by-section snap navigation that prevents the user from skimming.
- "Scroll-jacking" entrance animations that lock the scroll until they complete.
These confuse users because the OS scroll feels broken — the same gesture produces different results in different contexts.
When scroll-snap is the right answer
Limited cases:
- Horizontal carousels — scroll-snap-x on a single-row carousel is the right answer. The user expects each card to land aligned.
- Image galleries with explicit slides — vertical scroll-snap on a presentation-style page with discrete slides.
- Story-driven onboarding — first-time experiences where you specifically want each "step" to land precisely.
In all these cases, the vertical page scroll should still be free. Snap only the contained scroll, not the page scroll.
Scroll-driven animations — judiciously
scroll-driven animations (the new CSS feature) are powerful and worth knowing. They let you scrub an animation as the user scrolls — e.g., a hero image scales up as the user enters its viewport.
The right uses:
- Reveal-on-scroll — content fades/scales in as it enters the viewport. Subtle.
- Progress indicators — a top-of-page progress bar fills as the user scrolls.
- Parallax (gentle) — backgrounds move at 0.7x scroll speed for depth. NEVER 0.3x or below (causes nausea).
The wrong uses:
- Anything that changes the scroll behavior itself.
- Anything that slows the user's perceived scroll.
- Anything that animates as the user scrolls up differently than down — feels broken.
When to apply
- Designing any landing page with a top nav.
- Reviewing a PR that adds sticky behavior or scroll-driven animation.
- Auditing for AI-default tells (ai-default-tells).
- Rows above the view change height and the reading position jumps: scroll-anchoring.
Gotcha
backdrop-filter: blur() is GPU-cheap but interacts weirdly with position: sticky and overflow: hidden parents in some browsers. Always test on Safari + Firefox before shipping a blurred sticky nav.
Also: scroll-snap on iOS Safari can interact poorly with the URL bar collapsing. Test on real iPhone before shipping snap-based layouts.
Sources
- guidelines.sh — "Background blur on sticky sections is an AI giveaway" + "Avoid scroll hijacking."
- web.dev — scroll-driven animations docs.
- Related: viewport-custom-design, ai-default-tells, transform-opacity-only.
layoutstickyscrollanti-pattern