title: Scrolling Text to Change Fixed Background Image on Scroll
body: <p>I'm looking for some help, I'm trying to recreate the homepage on this site.</p>
  
  <p><a href="https://madebyarticle.com/" rel="nofollow noreferrer">https://madebyarticle.com/</a></p>
  
  <p>I don't want to use Jquery, either Plain JS or Vue.</p>
  
  <p>I've got it to do most what I want it to but have a few issues.</p>
  
  <p><a href="https://codepen.io/JakeHenshall/pen/dyPmZmg" rel="nofollow noreferrer">Codepen Example</a></p>
  
  <p>HTML</p>
  
  <pre><code>    &lt;main id="parent" class="Loop js-loop"&gt;
    &lt;section&gt;
      &lt;h1 class="step1"&gt;One&lt;/h1&gt;
    &lt;/section&gt;
    &lt;section&gt;
      &lt;h1 class="step2"&gt;For&lt;/h1&gt;
    &lt;/section&gt;
    &lt;section&gt;
      &lt;h1 class="step3"&gt;All&lt;/h1&gt;
    &lt;/section&gt;
    &lt;section&gt;
      &lt;h1&gt;And&lt;/h1&gt;
    &lt;/section&gt;
    &lt;section&gt;
      &lt;h1&gt;All&lt;/h1&gt;
    &lt;/section&gt;
    &lt;section&gt;
      &lt;h1&gt;For&lt;/h1&gt;
    &lt;/section&gt;
  
    &lt;!--
    These blocks are the same as the first blocks to get that looping illusion going.
    You need to add clones to fill out a full viewport height.
    --&gt;
    &lt;section class="green is-clone"&gt;
      &lt;h1&gt;One&lt;/h1&gt;
    &lt;/section&gt;
    &lt;section class="red is-clone"&gt;
      &lt;h1&gt;For&lt;/h1&gt;
    &lt;/section&gt;
  &lt;/main&gt;
  </code></pre>
  
  <p>CSS</p>
  
  <pre><code>    html,
  body {
    height: 100%;
    overflow: hidden;
  }
  
  .Loop {
    position: relative;
    height: 100%;
    overflow: auto;
    -webkit-overflow-scrolling: touch;
  }
  
  section {
    position: relative;
    text-align: center;
  /*   min-height: 300px;
    max-height: 700px; */
    height: 100vh;
  }
  
  ::scrollbar {
    display: none;
  }
  
  body {
    font-family: "Avenir Next", Helvetica, sans-serif;
    font-weight: normal;
    font-size: 100%;
  }
  
  h1 {
    margin: 0;
    position: absolute;
    top: 50%;
    transform: translateY(-50%);
    width: 100%;
    font-size: 80px;
    letter-spacing: 5px;
  /*   color: #fff; */
    text-transform: uppercase;
  }
  
  .mystyle {
    background: red;
  }
  
  
  .mystyle1 {
      background-image: url(https://images.unsplash.com/photo-1528834379234-2de7f8328fd8?ixlib=rb-1.2.1&amp;auto=format&amp;fit=crop&amp;w=1920&amp;q=10);
  }
  
  .mystyle2 {
    background-image: url(https://images.unsplash.com/photo-1501854140801-50d01698950b?ixlib=rb-1.2.1&amp;ixid=eyJhcHBfaWQiOjEyMDd9&amp;auto=format&amp;fit=crop&amp;w=2600&amp;q=80);
  }
  </code></pre>
  
  <p>JS</p>
  
  <pre><code>    var doc = window.document,
    context = doc.querySelector(".js-loop"),
    clones = context.querySelectorAll(".is-clone"),
    disableScroll = false,
    scrollHeight = 0,
    scrollPos = 0,
    clonesHeight = 0,
    i = 0;
  
  function getScrollPos() {
    return (context.pageYOffset || context.scrollTop) - (context.clientTop || 0);
  }
  
  function setScrollPos(pos) {
    context.scrollTop = pos;
  }
  
  function getClonesHeight() {
    clonesHeight = 0;
  
    for (i = 0; i &lt; clones.length; i += 1) {
      clonesHeight = clonesHeight + clones[i].offsetHeight;
    }
  
    return clonesHeight;
  }
  
  function reCalc() {
    scrollPos = getScrollPos();
    scrollHeight = context.scrollHeight;
    clonesHeight = getClonesHeight();
  
    if (scrollPos &lt;= 0) {
      setScrollPos(1); // Scroll 1 pixel to allow upwards scrolling
    }
  }
  
  function scrollUpdate() {
    if (!disableScroll) {
      scrollPos = getScrollPos();
  
      if (clonesHeight + scrollPos &gt;= scrollHeight) {
        // Scroll to the top when you’ve reached the bottom
        setScrollPos(1); // Scroll down 1 pixel to allow upwards scrolling
        disableScroll = true;
      } else if (scrollPos &lt;= 0) {
        // Scroll to the bottom when you reach the top
        setScrollPos(scrollHeight - clonesHeight);
        disableScroll = true;
      }
    }
  
    if (disableScroll) {
      // Disable scroll-jumping for a short time to avoid flickering
      window.setTimeout(function() {
        disableScroll = false;
      }, 40);
    }
  }
  
  function init() {
    reCalc();
  
    context.addEventListener(
      "scroll",
      function() {
        window.requestAnimationFrame(scrollUpdate);
      },
      false
    );
  
    window.addEventListener(
      "resize",
      function() {
        window.requestAnimationFrame(reCalc);
      },
      false
    );
  }
  
  if (document.readyState !== "loading") {
    init();
  } else {
    doc.addEventListener("DOMContentLoaded", init, false);
  }
  
  // Just for this demo: Center the middle block on page load
  window.onload = function() {
    setScrollPos(
      Math.round(
        clones[0].getBoundingClientRect().top +
          getScrollPos() -
          (context.offsetHeight - clones[0].offsetHeight) / 2
      )
    );
  };
  
  
  
  
  
  const images = document.querySelectorAll('h1');
  
  observer = new IntersectionObserver((entries) =&gt; {
    entries.forEach(entry =&gt; {
      if (entry.intersectionRatio &gt; 0) {
        entry.target.classList.add('active');
      } else {
        entry.target.classList.remove('active');
      }
    });
  });
  
  images.forEach(image =&gt; {
    observer.observe(image);
  });
  
  const header = document.getElementById("parent");
  const sectionOne = document.querySelector("h1.step1");
  const sectionTwo = document.querySelector("h1.step2");
  const sectionThree = document.querySelector("h1.step3");
  
  const sectionOneObserver = new IntersectionObserver(function(
    entries,
    sectionOneObserver
  ) {
    entries.forEach(entry =&gt; {
      if (!entry.isIntersecting) {
        header.classList.add("mystyle");
      } else {
        header.classList.remove("mystyle");
      }
    });
  });
  
  sectionOneObserver.observe(sectionOne);
  
  const sectionTwoObserver = new IntersectionObserver(function(
    entries,
    sectionTwoObserver
  ) {
    entries.forEach(entry =&gt; {
      if (!entry.isIntersecting) {
        header.classList.add("mystyle1");
      } else {
        header.classList.remove("mystyle1");
      }
    });
  });
  
  sectionTwoObserver.observe(sectionTwo);
  
  const sectionThreeObserver = new IntersectionObserver(function(
    entries,
    sectionThreeObserver
  ) {
    entries.forEach(entry =&gt; {
      if (!entry.isIntersecting) {
        header.classList.add("mystyle2");
      } else {
        header.classList.remove("mystyle2");
      }
    });
  });
  
  sectionThreeObserver.observe(sectionThree);
  
  
  
  
  
  
  // if (document.querySelectorAll('h1.step1.active')){
  //   document.getElementById("parent").classList.toggle("mystyle");
  //   } else {
  //     document.getElementById("parent").classList.remove("mystyle");
  // }
  
  
  // if (document.classList.contains("h1.step1.active")) {
  //     document.getElementById("parent").classList.add("mystyle");
  // } else {
  //     document.getElementById("parent").classList.remove("mystyle");
  // }
  </code></pre>
  
  <ol>
  <li><p>I'm having to duplicate the IntersectionObserver for every image I need, is there a cleaner way todo this?</p></li>
  <li><p>At some points, there are 2 active states so it doesn't display any image only a background colour.</p></li>
  <li><p>What would be the best way to fade the image on change like the example website?</p></li>
  </ol>
  
  <p>Are there any examples or scripts that can do what I'm trying todo?</p>
  
  <p>Thanks</p>