javascriptsticky

Implementing a sticky titles feature


I am trying to implement a sticky titles feature, and I think I am getting too complicated.

This is where I am right now:

class StickyTitles {
  constructor(titlesSelector, containerSelector, distanceFromTopDetection) {
    this.titles = Array.from(document.querySelectorAll(titlesSelector));
    this.container = document.querySelector(containerSelector);

    // Security buffer number to check if the intersection has happened in the top of the container
    this.distanceFromTopDetection = distanceFromTopDetection;
  }

  start() {
    this.setAllTitlesSticky();
    let observer = new IntersectionObserver(this.observerCallback.bind(this), this.observerOptions());
    this.titles.forEach( (e) => observer.observe(e) );
  }

  setAllTitlesSticky() {
    this.titles.forEach((e) => {
      e.style.position = "sticky";
      e.style.top = "0px";
      e.style.zIndex = "9999";
    });
  }

  observerOptions() {
    console.log("this.container:", this.container);
    const containerPaddingTop = window.getComputedStyle(this.container).getPropertyValue("padding-top");
    const containerPaddingTopInPx = parseInt(containerPaddingTop);
    console.log("containerPaddingTop:", containerPaddingTop);
    console.log("containerPaddingTopInPx:", containerPaddingTopInPx);

    return {
      root: this.container,
      rootMargin: `-${containerPaddingTopInPx + 10}px 0px 0px 0px`,
      threshold: [1],
    };
  }

  observerCallback(entries, _observer) {
    console.log("observerCallback");

    // Each entry describes an intersection change for one observed
    // target element:
    //   entry.boundingClientRect
    //   entry.intersectionRatio
    //   entry.intersectionRect
    //   entry.isIntersecting
    //   entry.rootBounds
    //   entry.target
    //   entry.time
    entries.forEach( (e) => this.intersectionEvent(e) );
  }

  intersectionEvent(entry) {
    const isIntersecting = entry.isIntersecting;
    const top = entry.boundingClientRect.top;

    console.log("intersectionEvent:", entry.target.innerText);
    console.log("isIntersecting:", isIntersecting);
    console.log("top:", top);

    console.log("intersectionRect.top:", entry.intersectionRect.top);
    console.log("rootBounds.top:", entry.rootBounds.top);

    console.log("intersectionRect.bottom:", entry.intersectionRect.bottom);
    console.log("rootBounds.bottom:", entry.rootBounds.bottom);

    if (isIntersecting && Math.abs(entry.intersectionRect.top - entry.rootBounds.top) < this.distanceFromTopDetection) {
      this.delinkTop(entry.target);
    } else if (!isIntersecting && Math.abs(entry.intersectionRect.top - entry.rootBounds.top) < this.distanceFromTopDetection) {
      this.linkTop(entry.target)
    }
  }
  linkTop(element) {
    console.log("linkTop:", element);
    this.allPreviousElementsTransparent(element, this.titles);
    this.allNextElementsVisible(element, this.titles);
    this.elementVisible(element)
  }

  delinkTop(element) {
    console.log("delinkTop:", element);
    this.previousElementVisible(element, this.titles);
  }

  allPreviousElementsTransparent(element) {
    console.log("allPreviousElementsTransparent:", element);
    const index = this.indexElement(element);
    console.log("index:", index);

    // First element has not previous
    if (index === 0) return;

    const previousElements = this.titles.slice(0, index);
    previousElements.forEach((e) => this.elementTransparent(e));
  }

  allNextElementsVisible(element) {
    console.log("allNextElementsVisible:", element);
    const index = this.indexElement(element);

    // Last element has not next
    if (index === this.titles.size - 1) return;

    const nextElements = this.titles.slice(index + 1);
    nextElements.forEach((e) => this.elementVisible(e));
  }

  previousElementVisible(element) {
    console.log("previousElementVisible:", element);

    // First element has not previous
    if (this.indexElement(element) === 0) return;

    const previousElement = this.titles[this.indexElement(element) - 1];
    this.elementVisible(previousElement)
  }

  elementVisible(element) {
    console.log("elementVisible:", element);
    element.classList.remove("transparent");
    element.classList.add("visible");
  }

  elementTransparent(element) {
    console.log("elementTransparent:", element);
    element.classList.remove("visible");
    element.classList.add("transparent");
  }

  indexElement(element) {
    const result =
      this.titles.findIndex((familyElement) => {
        return familyElement == element;
      });

    return result;
  }
}

// new StickyTitles(".message.role-user", "#messages-list", 200).start();

new StickyTitles("h1", "#container", 20).start();
#container {
  margin: 100px;
  height: 400px;
  overflow-y: scroll;
  padding: 50px;
}

#container h1 {
  display: inline;
  background-color: darkkhaki;
}

#container h1.transparent {
  transition: opacity 0.3s;
  opacity: 0;
}

#container h1.visible {
  transition: opacity 0.3s;
  opacity: 1;
}
<html>
<head>
  <title>Test</title>
</head>
<body>
  <div id="container">
    <h1>Title 1</h1>
    <p>
      Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum nec leo sit amet est sollicitudin viverra. Etiam
      tincidunt erat et est facilisis, id laoreet sapien bibendum. Nulla rutrum odio sed est vulputate, vitae luctus massa
      hendrerit. Sed sed urna venenatis sem tristique finibus. Donec tristique nisl nibh. Sed non hendrerit nulla. Nulla non
      leo diam.

      Nullam eu magna consequat, laoreet purus nec, luctus augue. Integer porttitor eros at tellus porta tempus. Curabitur
      imperdiet odio velit, ac commodo magna tristique sed. Maecenas ornare blandit mi, in accumsan tellus aliquam vel. Sed
      enim dui, tincidunt at nisi quis, accumsan tempor justo. Donec eget justo interdum, scelerisque ante nec, varius neque.
      Aenean odio tortor, suscipit nec aliquam quis, viverra eget enim. In pharetra aliquam diam, sed sollicitudin elit varius
      id. Morbi pulvinar tincidunt dolor.

      Sed id urna eleifend, vulputate libero ac, tristique ipsum. Nullam porta erat ut tellus vestibulum ultrices. Maecenas
      non est a diam eleifend dictum non vitae magna. Morbi aliquet viverra nunc et laoreet. Integer massa urna, maximus sed
      mi nec, consequat consequat erat. Nulla facilisi. Nullam feugiat ligula vel elit fringilla commodo. Integer a posuere
      nibh, at porttitor risus. Morbi id sem facilisis odio dapibus volutpat sit amet id leo. Nunc id volutpat urna. Nunc eget
      ex vel nibh tincidunt venenatis. Proin congue quis mauris ut luctus.
    </p>

    <h1>Title facilisis sit amet, consectetur</h1>
    <p>
      Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum nec leo sit amet est sollicitudin viverra. Etiam
      tincidunt erat et est facilisis, id laoreet sapien bibendum. Nulla rutrum odio sed est vulputate, vitae luctus massa
      hendrerit. Sed sed urna venenatis sem tristique finibus. Donec tristique nisl nibh. Sed non hendrerit nulla. Nulla non
      leo diam.

      Nullam eu magna consequat, laoreet purus nec, luctus augue. Integer porttitor eros at tellus porta tempus. Curabitur
      imperdiet odio velit, ac commodo magna tristique sed. Maecenas ornare blandit mi, in accumsan tellus aliquam vel. Sed
      enim dui, tincidunt at nisi quis, accumsan tempor justo. Donec eget justo interdum, scelerisque ante nec, varius
      neque.
      Aenean odio tortor, suscipit nec aliquam quis, viverra eget enim. In pharetra aliquam diam, sed sollicitudin elit
      varius
      id. Morbi pulvinar tincidunt dolor.

      Sed id urna eleifend, vulputate libero ac, tristique ipsum. Nullam porta erat ut tellus vestibulum ultrices. Maecenas
      non est a diam eleifend dictum non vitae magna. Morbi aliquet viverra nunc et laoreet. Integer massa urna, maximus sed
      mi nec, consequat consequat erat. Nulla facilisi. Nullam feugiat ligula vel elit fringilla commodo. Integer a posuere
      nibh, at porttitor risus. Morbi id sem facilisis odio dapibus volutpat sit amet id leo. Nunc id volutpat urna. Nunc
      eget
      ex vel nibh tincidunt venenatis. Proin congue quis mauris ut luctus.
    </p>

    <h1>Title dolor sit amet</h1>
    <p>
      Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum nec leo sit amet est sollicitudin viverra. Etiam
      tincidunt erat et est facilisis, id laoreet sapien bibendum. Nulla rutrum odio sed est vulputate, vitae luctus massa
      hendrerit. Sed sed urna venenatis sem tristique finibus. Donec tristique nisl nibh. Sed non hendrerit nulla. Nulla non
      leo diam.

      Nullam eu magna consequat, laoreet purus nec, luctus augue. Integer porttitor eros at tellus porta tempus. Curabitur
      imperdiet odio velit, ac commodo magna tristique sed. Maecenas ornare blandit mi, in accumsan tellus aliquam vel. Sed
      enim dui, tincidunt at nisi quis, accumsan tempor justo. Donec eget justo interdum, scelerisque ante nec, varius
      neque.
      Aenean odio tortor, suscipit nec aliquam quis, viverra eget enim. In pharetra aliquam diam, sed sollicitudin elit
      varius
      id. Morbi pulvinar tincidunt dolor.

      Sed id urna eleifend, vulputate libero ac, tristique ipsum. Nullam porta erat ut tellus vestibulum ultrices. Maecenas
      non est a diam eleifend dictum non vitae magna. Morbi aliquet viverra nunc et laoreet. Integer massa urna, maximus sed
      mi nec, consequat consequat erat. Nulla facilisi. Nullam feugiat ligula vel elit fringilla commodo. Integer a posuere
      nibh, at porttitor risus. Morbi id sem facilisis odio dapibus volutpat sit amet id leo. Nunc id volutpat urna. Nunc
      eget
      ex vel nibh tincidunt venenatis. Proin congue quis mauris ut luctus.
    </p>

    <h1>Title consequat consequat erat. Nulla facilisi</h1>
    <p>
      Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum nec leo sit amet est sollicitudin viverra. Etiam
      tincidunt erat et est facilisis, id laoreet sapien bibendum. Nulla rutrum odio sed est vulputate, vitae luctus massa
      hendrerit. Sed sed urna venenatis sem tristique finibus. Donec tristique nisl nibh. Sed non hendrerit nulla. Nulla non
      leo diam.

      Nullam eu magna consequat, laoreet purus nec, luctus augue. Integer porttitor eros at tellus porta tempus. Curabitur
      imperdiet odio velit, ac commodo magna tristique sed. Maecenas ornare blandit mi, in accumsan tellus aliquam vel. Sed
      enim dui, tincidunt at nisi quis, accumsan tempor justo. Donec eget justo interdum, scelerisque ante nec, varius
      neque.
      Aenean odio tortor, suscipit nec aliquam quis, viverra eget enim. In pharetra aliquam diam, sed sollicitudin elit
      varius
      id. Morbi pulvinar tincidunt dolor.

      Sed id urna eleifend, vulputate libero ac, tristique ipsum. Nullam porta erat ut tellus vestibulum ultrices. Maecenas
      non est a diam eleifend dictum non vitae magna. Morbi aliquet viverra nunc et laoreet. Integer massa urna, maximus sed
      mi nec, consequat consequat erat. Nulla facilisi. Nullam feugiat ligula vel elit fringilla commodo. Integer a posuere
      nibh, at porttitor risus. Morbi id sem facilisis odio dapibus volutpat sit amet id leo. Nunc id volutpat urna. Nunc
      eget
      ex vel nibh tincidunt venenatis. Proin congue quis mauris ut luctus.
    </p>

    <h1>Title at nisi quis</h1>
    <p>
      Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum nec leo sit amet est sollicitudin viverra. Etiam
      tincidunt erat et est facilisis, id laoreet sapien bibendum. Nulla rutrum odio sed est vulputate, vitae luctus massa
      hendrerit. Sed sed urna venenatis sem tristique finibus. Donec tristique nisl nibh. Sed non hendrerit nulla. Nulla non
      leo diam.

      Nullam eu magna consequat, laoreet purus nec, luctus augue. Integer porttitor eros at tellus porta tempus. Curabitur
      imperdiet odio velit, ac commodo magna tristique sed. Maecenas ornare blandit mi, in accumsan tellus aliquam vel. Sed
      enim dui, tincidunt at nisi quis, accumsan tempor justo. Donec eget justo interdum, scelerisque ante nec, varius
      neque.
      Aenean odio tortor, suscipit nec aliquam quis, viverra eget enim. In pharetra aliquam diam, sed sollicitudin elit
      varius
      id. Morbi pulvinar tincidunt dolor.

      Sed id urna eleifend, vulputate libero ac, tristique ipsum. Nullam porta erat ut tellus vestibulum ultrices. Maecenas
      non est a diam eleifend dictum non vitae magna. Morbi aliquet viverra nunc et laoreet. Integer massa urna, maximus sed
      mi nec, consequat consequat erat. Nulla facilisi. Nullam feugiat ligula vel elit fringilla commodo. Integer a posuere
      nibh, at porttitor risus. Morbi id sem facilisis odio dapibus volutpat sit amet id leo. Nunc id volutpat urna. Nunc
      eget
      ex vel nibh tincidunt venenatis. Proin congue quis mauris ut luctus.
    </p>

    <h1>Title Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum nec leo sit amet est sollicitudin viverra. Etiam
    tincidunt erat et est facilisis, id laoreet sapien bibendum. Nulla rutrum odio sed est vulputate, vitae luctus massa
    hendrerit</h1>
    <p>
      Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum nec leo sit amet est sollicitudin viverra. Etiam
      tincidunt erat et est facilisis, id laoreet sapien bibendum. Nulla rutrum odio sed est vulputate, vitae luctus massa
      hendrerit. Sed sed urna venenatis sem tristique finibus. Donec tristique nisl nibh. Sed non hendrerit nulla. Nulla non
      leo diam.

      Nullam eu magna consequat, laoreet purus nec, luctus augue. Integer porttitor eros at tellus porta tempus. Curabitur
      imperdiet odio velit, ac commodo magna tristique sed. Maecenas ornare blandit mi, in accumsan tellus aliquam vel. Sed
      enim dui, tincidunt at nisi quis, accumsan tempor justo. Donec eget justo interdum, scelerisque ante nec, varius
      neque.
      Aenean odio tortor, suscipit nec aliquam quis, viverra eget enim. In pharetra aliquam diam, sed sollicitudin elit
      varius
      id. Morbi pulvinar tincidunt dolor.

      Sed id urna eleifend, vulputate libero ac, tristique ipsum. Nullam porta erat ut tellus vestibulum ultrices. Maecenas
      non est a diam eleifend dictum non vitae magna. Morbi aliquet viverra nunc et laoreet. Integer massa urna, maximus sed
      mi nec, consequat consequat erat. Nulla facilisi. Nullam feugiat ligula vel elit fringilla commodo. Integer a posuere
      nibh, at porttitor risus. Morbi id sem facilisis odio dapibus volutpat sit amet id leo. Nunc id volutpat urna. Nunc
      eget
      ex vel nibh tincidunt venenatis. Proin congue quis mauris ut luctus.
    </p>
  </div>
</body>
</html>

Codepen

The main point is that all the titles are position: sticky. This was easy. But then I had to make the previous titles invisible so they don't get messy on the back of the actual title.

This is where things started to get complicated.

I managed to find a solution by detecting the intersection with the top or bottom of the container and making the other siblings visible or invisible.

But then I realized that if I scroll too fast back and forth, the title states start to get messy, like being invisible when they should be visible and vice versa.

I tried to minimize the bugs by making other siblings visible/invisible in many different cases to double-check that the state was right.

Still, the intersection mechanism is not very solid, and I have situations where the titles are not in the right state.

It would be easy if I had a way to:

I could call this method on every scroll event, and it should work. But I can't find a way to detect what titles are actually "stuck" on the top (I can't find an event for that). Only by intersections and, as mentioned, they are not trustable in quick scrolls.


Solution

  • You could use a scroll event listener and, for each header, check whether it's bottom is touching or crossing the top of the next header, and if it is, hide it.

    const headers = Array.from(document.querySelectorAll("#container h1"));
    
    const container = document.getElementById("container");
    
    headers.forEach((header, i) => {
      // Ignore last header
      if (i === headers.length - 1) return;
    
      const nextHeader = headers[i + 1];
      container.addEventListener("scroll", () => {
        const nextTop = nextHeader.getBoundingClientRect().top;
        const currentBottom = header.getBoundingClientRect().bottom;
    
        const isOverlapping = currentBottom > nextTop;
        header.style.opacity = isOverlapping ? 0 : 1;
      });
    });
    #container {
      margin: 100px;
      height: 400px;
      overflow-y: scroll;
      padding: 50px;
    }
    
    #container h1 {
      position: sticky;
      top: 50px;
      transition: opacity 600ms;
      background-color: rgba(219, 231, 0, 0.3);
    }
    <html>
    <head>
      <title>Test</title>
    </head>
    <body>
      <div id="container">
        <h1>Title 1</h1>
        <p>
          Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum nec leo sit amet est sollicitudin viverra. Etiam
          tincidunt erat et est facilisis, id laoreet sapien bibendum. Nulla rutrum odio sed est vulputate, vitae luctus massa
          hendrerit. Sed sed urna venenatis sem tristique finibus. Donec tristique nisl nibh. Sed non hendrerit nulla. Nulla non
          leo diam.
    
          Nullam eu magna consequat, laoreet purus nec, luctus augue. Integer porttitor eros at tellus porta tempus. Curabitur
          imperdiet odio velit, ac commodo magna tristique sed. Maecenas ornare blandit mi, in accumsan tellus aliquam vel. Sed
          enim dui, tincidunt at nisi quis, accumsan tempor justo. Donec eget justo interdum, scelerisque ante nec, varius neque.
          Aenean odio tortor, suscipit nec aliquam quis, viverra eget enim. In pharetra aliquam diam, sed sollicitudin elit varius
          id. Morbi pulvinar tincidunt dolor.
    
          Sed id urna eleifend, vulputate libero ac, tristique ipsum. Nullam porta erat ut tellus vestibulum ultrices. Maecenas
          non est a diam eleifend dictum non vitae magna. Morbi aliquet viverra nunc et laoreet. Integer massa urna, maximus sed
          mi nec, consequat consequat erat. Nulla facilisi. Nullam feugiat ligula vel elit fringilla commodo. Integer a posuere
          nibh, at porttitor risus. Morbi id sem facilisis odio dapibus volutpat sit amet id leo. Nunc id volutpat urna. Nunc eget
          ex vel nibh tincidunt venenatis. Proin congue quis mauris ut luctus.
        </p>
    
        <h1>Title facilisis sit amet, consectetur</h1>
        <p>
          Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum nec leo sit amet est sollicitudin viverra. Etiam
          tincidunt erat et est facilisis, id laoreet sapien bibendum. Nulla rutrum odio sed est vulputate, vitae luctus massa
          hendrerit. Sed sed urna venenatis sem tristique finibus. Donec tristique nisl nibh. Sed non hendrerit nulla. Nulla non
          leo diam.
    
          Nullam eu magna consequat, laoreet purus nec, luctus augue. Integer porttitor eros at tellus porta tempus. Curabitur
          imperdiet odio velit, ac commodo magna tristique sed. Maecenas ornare blandit mi, in accumsan tellus aliquam vel. Sed
          enim dui, tincidunt at nisi quis, accumsan tempor justo. Donec eget justo interdum, scelerisque ante nec, varius
          neque.
          Aenean odio tortor, suscipit nec aliquam quis, viverra eget enim. In pharetra aliquam diam, sed sollicitudin elit
          varius
          id. Morbi pulvinar tincidunt dolor.
    
          Sed id urna eleifend, vulputate libero ac, tristique ipsum. Nullam porta erat ut tellus vestibulum ultrices. Maecenas
          non est a diam eleifend dictum non vitae magna. Morbi aliquet viverra nunc et laoreet. Integer massa urna, maximus sed
          mi nec, consequat consequat erat. Nulla facilisi. Nullam feugiat ligula vel elit fringilla commodo. Integer a posuere
          nibh, at porttitor risus. Morbi id sem facilisis odio dapibus volutpat sit amet id leo. Nunc id volutpat urna. Nunc
          eget
          ex vel nibh tincidunt venenatis. Proin congue quis mauris ut luctus.
        </p>
    
        <h1>Title dolor sit amet</h1>
        <p>
          Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum nec leo sit amet est sollicitudin viverra. Etiam
          tincidunt erat et est facilisis, id laoreet sapien bibendum. Nulla rutrum odio sed est vulputate, vitae luctus massa
          hendrerit. Sed sed urna venenatis sem tristique finibus. Donec tristique nisl nibh. Sed non hendrerit nulla. Nulla non
          leo diam.
    
          Nullam eu magna consequat, laoreet purus nec, luctus augue. Integer porttitor eros at tellus porta tempus. Curabitur
          imperdiet odio velit, ac commodo magna tristique sed. Maecenas ornare blandit mi, in accumsan tellus aliquam vel. Sed
          enim dui, tincidunt at nisi quis, accumsan tempor justo. Donec eget justo interdum, scelerisque ante nec, varius
          neque.
          Aenean odio tortor, suscipit nec aliquam quis, viverra eget enim. In pharetra aliquam diam, sed sollicitudin elit
          varius
          id. Morbi pulvinar tincidunt dolor.
    
          Sed id urna eleifend, vulputate libero ac, tristique ipsum. Nullam porta erat ut tellus vestibulum ultrices. Maecenas
          non est a diam eleifend dictum non vitae magna. Morbi aliquet viverra nunc et laoreet. Integer massa urna, maximus sed
          mi nec, consequat consequat erat. Nulla facilisi. Nullam feugiat ligula vel elit fringilla commodo. Integer a posuere
          nibh, at porttitor risus. Morbi id sem facilisis odio dapibus volutpat sit amet id leo. Nunc id volutpat urna. Nunc
          eget
          ex vel nibh tincidunt venenatis. Proin congue quis mauris ut luctus.
        </p>
    
        <h1>Title consequat consequat erat. Nulla facilisi</h1>
        <p>
          Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum nec leo sit amet est sollicitudin viverra. Etiam
          tincidunt erat et est facilisis, id laoreet sapien bibendum. Nulla rutrum odio sed est vulputate, vitae luctus massa
          hendrerit. Sed sed urna venenatis sem tristique finibus. Donec tristique nisl nibh. Sed non hendrerit nulla. Nulla non
          leo diam.
    
          Nullam eu magna consequat, laoreet purus nec, luctus augue. Integer porttitor eros at tellus porta tempus. Curabitur
          imperdiet odio velit, ac commodo magna tristique sed. Maecenas ornare blandit mi, in accumsan tellus aliquam vel. Sed
          enim dui, tincidunt at nisi quis, accumsan tempor justo. Donec eget justo interdum, scelerisque ante nec, varius
          neque.
          Aenean odio tortor, suscipit nec aliquam quis, viverra eget enim. In pharetra aliquam diam, sed sollicitudin elit
          varius
          id. Morbi pulvinar tincidunt dolor.
    
          Sed id urna eleifend, vulputate libero ac, tristique ipsum. Nullam porta erat ut tellus vestibulum ultrices. Maecenas
          non est a diam eleifend dictum non vitae magna. Morbi aliquet viverra nunc et laoreet. Integer massa urna, maximus sed
          mi nec, consequat consequat erat. Nulla facilisi. Nullam feugiat ligula vel elit fringilla commodo. Integer a posuere
          nibh, at porttitor risus. Morbi id sem facilisis odio dapibus volutpat sit amet id leo. Nunc id volutpat urna. Nunc
          eget
          ex vel nibh tincidunt venenatis. Proin congue quis mauris ut luctus.
        </p>
    
        <h1>Title at nisi quis</h1>
        <p>
          Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum nec leo sit amet est sollicitudin viverra. Etiam
          tincidunt erat et est facilisis, id laoreet sapien bibendum. Nulla rutrum odio sed est vulputate, vitae luctus massa
          hendrerit. Sed sed urna venenatis sem tristique finibus. Donec tristique nisl nibh. Sed non hendrerit nulla. Nulla non
          leo diam.
    
          Nullam eu magna consequat, laoreet purus nec, luctus augue. Integer porttitor eros at tellus porta tempus. Curabitur
          imperdiet odio velit, ac commodo magna tristique sed. Maecenas ornare blandit mi, in accumsan tellus aliquam vel. Sed
          enim dui, tincidunt at nisi quis, accumsan tempor justo. Donec eget justo interdum, scelerisque ante nec, varius
          neque.
          Aenean odio tortor, suscipit nec aliquam quis, viverra eget enim. In pharetra aliquam diam, sed sollicitudin elit
          varius
          id. Morbi pulvinar tincidunt dolor.
    
          Sed id urna eleifend, vulputate libero ac, tristique ipsum. Nullam porta erat ut tellus vestibulum ultrices. Maecenas
          non est a diam eleifend dictum non vitae magna. Morbi aliquet viverra nunc et laoreet. Integer massa urna, maximus sed
          mi nec, consequat consequat erat. Nulla facilisi. Nullam feugiat ligula vel elit fringilla commodo. Integer a posuere
          nibh, at porttitor risus. Morbi id sem facilisis odio dapibus volutpat sit amet id leo. Nunc id volutpat urna. Nunc
          eget
          ex vel nibh tincidunt venenatis. Proin congue quis mauris ut luctus.
        </p>
    
        <h1>Title Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum nec leo sit amet est sollicitudin viverra. Etiam
        tincidunt erat et est facilisis, id laoreet sapien bibendum. Nulla rutrum odio sed est vulputate, vitae luctus massa
        hendrerit</h1>
        <p>
          Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum nec leo sit amet est sollicitudin viverra. Etiam
          tincidunt erat et est facilisis, id laoreet sapien bibendum. Nulla rutrum odio sed est vulputate, vitae luctus massa
          hendrerit. Sed sed urna venenatis sem tristique finibus. Donec tristique nisl nibh. Sed non hendrerit nulla. Nulla non
          leo diam.
    
          Nullam eu magna consequat, laoreet purus nec, luctus augue. Integer porttitor eros at tellus porta tempus. Curabitur
          imperdiet odio velit, ac commodo magna tristique sed. Maecenas ornare blandit mi, in accumsan tellus aliquam vel. Sed
          enim dui, tincidunt at nisi quis, accumsan tempor justo. Donec eget justo interdum, scelerisque ante nec, varius
          neque.
          Aenean odio tortor, suscipit nec aliquam quis, viverra eget enim. In pharetra aliquam diam, sed sollicitudin elit
          varius
          id. Morbi pulvinar tincidunt dolor.
    
          Sed id urna eleifend, vulputate libero ac, tristique ipsum. Nullam porta erat ut tellus vestibulum ultrices. Maecenas
          non est a diam eleifend dictum non vitae magna. Morbi aliquet viverra nunc et laoreet. Integer massa urna, maximus sed
          mi nec, consequat consequat erat. Nulla facilisi. Nullam feugiat ligula vel elit fringilla commodo. Integer a posuere
          nibh, at porttitor risus. Morbi id sem facilisis odio dapibus volutpat sit amet id leo. Nunc id volutpat urna. Nunc
          eget
          ex vel nibh tincidunt venenatis. Proin congue quis mauris ut luctus.
        </p>
        </div>
    </body>
    </html>

    You can set the relative position thresholds according to how you want it to behave. Since they're set to position: sticky, all "stuck" elements will have the same top position. So you could also have the prev. header disappear when its top position matches the next header's, but then you'll get some overlap until the next one does stick, that's why I chose to hide them when their bottoms touch the tops of the next ones.