Sticky Header
Headers that follow the user on scroll — always-sticky, hide-on-scroll, transparent-to-solid, slim-on-scroll, and progress-bar variants.
Always Sticky
The header sticks to the top of its scroll container at all times. Shadow appears once the user has scrolled past the natural header position.
↕ Scroll this panel to see the shadow appear.
Classes: sticky top-0 z-10 on the header. Shadow toggled with Alpine on @scroll.
Hide on Scroll Down / Reveal on Scroll Up
Hides when the user scrolls down to reclaim vertical space; slides back in on upward scroll. Common on mobile-first content sites.
↓ Scroll down — header hides. ↑ Scroll up — header reappears.
Alpine compares scrollTop vs lastY on each scroll event. transform: translateY(-100%) hides without reflow.
Transparent → Solid on Scroll
Starts fully transparent over a hero image, then transitions to a solid background with a backdrop blur once the user scrolls past the hero.
Hero section — header is transparent here
↕ Scroll up past the hero to see the header become transparent again.
Alpine toggles pastHero at 120px. Header transitions background-color + backdrop-filter; text colors transition separately.
Slim on Scroll
The header compresses its padding once the user has scrolled, recovering vertical space without hiding entirely.
↓ Scroll to watch the header shrink. ↑ Scroll back up to see it expand.
Padding transitions from py-4 → py-1.5. Custom transition: padding required — Tailwind's transition-all is too broad for layout properties.
Reading Progress Bar
A thin progress bar under the sticky header fills as the user reads through the article. Width is calculated from scrollTop / (scrollHeight - clientHeight).
The Architecture of Attention
Scroll through this article to watch the progress bar fill. The bar width is a live percentage of how far through the content the reader has scrolled.
Progress tracking is calculated from scrollTop divided by the difference between scrollHeight and clientHeight — the portion of the document not yet visible in the viewport.
Unlike a time-based estimate, scroll-based progress reflects actual reading position without any assumptions about reading speed.
The progress bar resets to zero when the user returns to the top. It never exceeds 100%, and the transition easing is kept intentionally fast (80ms linear) to feel instantaneous rather than lagged.
This pattern is especially useful for long-form editorial content, documentation, and technical articles where knowing "how far through" you are helps plan a reading session.
The implementation here is entirely self-contained: no third-party libraries, no scroll event debouncing needed, and no IntersectionObserver — the Alpine @scroll handler is sufficient at this fidelity.
Progress: scrollTop / (scrollHeight − clientHeight) × 100. Width applied via :style — runtime value, not a static Tailwind class.