Adaptive Editorial Header

A premium header that changes density and behavior as reading depth increases.

This experiment requires full-page rendering.

Open live demo

HTML

<div class="adaptive-editorial-header-demo">
  <header class="adaptive-editorial-header" data-adaptive-header>
    <div class="adaptive-editorial-header__progress" aria-hidden="true">
      <span data-header-progress></span>
    </div>

    <div class="adaptive-editorial-header__inner">
      <p class="adaptive-editorial-header__eyebrow">Nebula Review</p>
      <h1>Designing For Depth, Not Just Arrival</h1>

      <div class="adaptive-editorial-header__meta">
        <span data-header-state>Opening cadence</span>
        <span>8 min read</span>
      </div>
    </div>
  </header>

  <main class="adaptive-editorial-story">
    <section class="adaptive-editorial-section" data-header-section="Opening cadence">
      <p class="adaptive-editorial-section__eyebrow">Section 01</p>
      <h2>Open with clarity, not noise</h2>
      <p>
        Premium editorial experiences rarely need a loud masthead once the reader commits. They need a calm frame that
        can introduce the story, then step back at the right moment.
      </p>
      <p>
        The header starts spacious and declarative, then compresses as the article earns attention and the reading depth
        increases.
      </p>
    </section>

    <section class="adaptive-editorial-section" data-header-section="Reading focus">
      <p class="adaptive-editorial-section__eyebrow">Section 02</p>
      <h2>Reduce chrome while momentum is high</h2>
      <p>
        Once a reader settles into a rhythm, the interface can afford to become denser. The title remains present, but
        secondary detail softens and the shell becomes lighter.
      </p>
      <p>
        Scroll direction matters too. When the user moves down with intent, the header yields space. When the user moves
        up, orientation returns immediately.
      </p>
    </section>

    <section class="adaptive-editorial-section" data-header-section="Deep reading">
      <p class="adaptive-editorial-section__eyebrow">Section 03</p>
      <h2>Support orientation without interruption</h2>
      <p>
        Deep reading does not mean abandoning navigation. It means keeping navigational signals compact enough that they
        reinforce context instead of competing with prose.
      </p>
      <p>
        The adaptive state here preserves the section label and progress, while maintaining a softer visual footprint.
      </p>
    </section>

    <section class="adaptive-editorial-section" data-header-section="Closing cadence">
      <p class="adaptive-editorial-section__eyebrow">Section 04</p>
      <h2>End with the same composure you started with</h2>
      <p>
        Near the end of a piece, the interface can gently reassert itself to signal completion and frame what comes next.
      </p>
      <p>
        The result is a header that behaves like an editorial companion rather than a fixed banner pasted above the page.
      </p>
    </section>
  </main>
</div>

CSS

.adaptive-editorial-header-demo {
  max-width: 920px;
  margin: 0 auto;
}

.adaptive-editorial-header {
  position: sticky;
  top: 18px;
  z-index: 5;
  margin-bottom: 26px;
  border: 1px solid rgba(255, 255, 255, 0.08);
  border-radius: 28px;
  overflow: hidden;
  background:
    linear-gradient(135deg, rgba(255, 255, 255, 0.12), transparent 45%),
    rgba(12, 14, 18, 0.82);
  backdrop-filter: blur(18px);
  box-shadow: 0 20px 48px rgba(0, 0, 0, 0.28);
  transition: transform 220ms ease, border-color 220ms ease, background 220ms ease;
}

.adaptive-editorial-header__progress {
  height: 3px;
  background: rgba(255, 255, 255, 0.08);
}

.adaptive-editorial-header__progress span {
  display: block;
  width: 0;
  height: 100%;
  background: linear-gradient(90deg, #13be9c, #faaf3b);
  transition: width 180ms linear;
}

.adaptive-editorial-header__inner {
  padding: 22px 24px 24px;
  transition: padding 220ms ease;
}

.adaptive-editorial-header__eyebrow,
.adaptive-editorial-section__eyebrow {
  margin: 0 0 10px;
  font-size: 0.78rem;
  text-transform: uppercase;
  letter-spacing: 0.18em;
  color: rgba(255, 255, 255, 0.6);
}

.adaptive-editorial-header h1 {
  margin: 0;
  max-width: 12ch;
  font-size: clamp(2.4rem, 5vw, 4rem);
  line-height: 0.94;
  color: #ffffff;
  transition: font-size 220ms ease, max-width 220ms ease;
}

.adaptive-editorial-header__meta {
  display: flex;
  flex-wrap: wrap;
  gap: 12px 18px;
  margin-top: 16px;
  color: rgba(255, 255, 255, 0.72);
}

.adaptive-editorial-header__meta span + span::before {
  content: '•';
  margin-right: 18px;
  color: rgba(255, 255, 255, 0.3);
}

.adaptive-editorial-header.is-condensed .adaptive-editorial-header__inner {
  padding-top: 14px;
  padding-bottom: 16px;
}

.adaptive-editorial-header.is-condensed h1 {
  max-width: none;
  font-size: clamp(1.5rem, 3vw, 2.1rem);
}

.adaptive-editorial-header.is-deep {
  border-color: rgba(19, 190, 156, 0.32);
}

.adaptive-editorial-header.is-hidden {
  transform: translateY(-112%);
}

.adaptive-editorial-story {
  display: grid;
  gap: 20px;
}

.adaptive-editorial-section {
  min-height: 72vh;
  padding: 34px;
  border-radius: 32px;
  border: 1px solid rgba(255, 255, 255, 0.08);
  background:
    linear-gradient(180deg, rgba(255, 255, 255, 0.05), rgba(255, 255, 255, 0.02)),
    rgba(10, 10, 12, 0.94);
}

.adaptive-editorial-section h2 {
  margin: 0 0 16px;
  max-width: 14ch;
  font-size: clamp(2rem, 4vw, 3.4rem);
  line-height: 0.96;
}

.adaptive-editorial-section p {
  max-width: 60ch;
  margin: 0;
  color: rgba(255, 255, 255, 0.82);
  line-height: 1.8;
  font-size: 1.06rem;
}

.adaptive-editorial-section p + p {
  margin-top: 14px;
}

JavaScript

(function () {
  const root = document.querySelector('.adaptive-editorial-header-demo');
  if (!root) return;

  const header = root.querySelector('[data-adaptive-header]');
  const progress = root.querySelector('[data-header-progress]');
  const state = root.querySelector('[data-header-state]');
  const sections = Array.from(root.querySelectorAll('[data-header-section]'));
  if (!header || !progress || !state || !sections.length) return;

  let lastScrollY = window.scrollY;

  function updateActiveSection() {
    const threshold = window.innerHeight * 0.42;
    let active = sections[0];

    sections.forEach(section => {
      if (section.getBoundingClientRect().top <= threshold) {
        active = section;
      }
    });

    state.textContent = active.dataset.headerSection;
  }

  function updateHeader() {
    const scrollTop = window.scrollY;
    const docHeight = document.documentElement.scrollHeight - window.innerHeight;
    const scrollProgress = docHeight > 0 ? (scrollTop / docHeight) * 100 : 0;
    const scrollingDown = scrollTop > lastScrollY + 8;
    const scrollingUp = scrollTop < lastScrollY - 8;

    progress.style.width = `${Math.max(0, Math.min(100, scrollProgress))}%`;
    header.classList.toggle('is-condensed', scrollTop > 140);
    header.classList.toggle('is-deep', scrollProgress > 55);

    if (scrollTop > 220 && scrollingDown) {
      header.classList.add('is-hidden');
    }

    if (scrollingUp || scrollTop < 80) {
      header.classList.remove('is-hidden');
    }

    updateActiveSection();
    lastScrollY = scrollTop;
  }

  window.addEventListener('scroll', updateHeader, { passive: true });
  updateHeader();
})();
  • Tech used Vanilla JS, WordPress-ready, No dependencies
  • Integration level Advanced (custom logic)
  • Performance safe Yes

What it solves

Keeps editorial framing present without letting a fixed masthead dominate the reading session.

Adaptive Editorial Header explores how an editorial shell can become quieter and denser once a reader is genuinely engaged. The headline opens with premium presence, then progressively compresses as scroll depth and direction signal stronger reading commitment.

The goal is not to animate for effect. It is to preserve orientation while giving the narrative more breathing room during the moments when attention matters most.