How to Implement a Scroll-Triggered Text Opacity Change in a Split-Section Layout Using HTML, CSS, & JS?

Hello Stack Overflow community,

I’ve come across a compelling visual effect on a split layout and am trying to recreate a similar functionality. You can see the effect in action here: https://stb-hornauer.de/. The layout features a static image on one side and text that changes on the other as the user scrolls down. I’m focused on the text opacity change that occurs with scrolling, not the image slider component.

I have a foundational understanding of HTML, CSS, and a bit of JavaScript. Any pointers or a sample code snippet that could help guide me toward achieving this scroll-linked text opacity effect would be greatly appreciated.

Thank you in advance for your time and help!

I’ve come this far so far, but it’s not like the example:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Scroll Animation</title>
    <style>
      .left-t {
        width: 50%;
        height: 100vh;
        padding-bottom: 14%;
        padding-left: 150px;
        padding-right: 100px;
        position: -webkit-sticky;
        position: sticky;
        top: 14%;
        bottom: 0;
        overflow: hidden;
      }

      .left_content_wrap {
        height: 100%;
        justify-content: flex-start;
        align-items: center;
        display: flex;
        position: relative;
      }

      .text_wrap {
        z-index: 1;
        height: auto;
        flex-flow: column;
        justify-content: flex-start;
        align-items: flex-start;
        padding-top: 40%;
        display: flex;
        position: absolute;
        top: 0%;
        bottom: 0%;
        left: 0%;
        right: 0%;
      }

      @media screen and (min-width: 1280px) {
        .text_wrap {
          flex-direction: column;
          display: flex;
        }
      }

      .div-block-22 {
        align-items: center;
        padding-bottom: 80px;
        display: flex;
      }

      .heading_h1.text_home {
        color: #363940;
        text-transform: none;
        flex: 0 auto;
        padding-bottom: 0;
        font-size: 35px;
        line-height: 38px;
      }

      .div-block-23 {
        height: 50%;
        align-items: flex-start;
        display: flex;
      }

      @media screen and (min-width: 1280px) {
        .div-block-23,
        .div-block-25 {
          max-width: 500px;
        }
      }

      .text_main {
        flex: 0 auto;
        padding-top: 0;
        display: block;
      }

      .text_wrap_2 {
        z-index: 2;
        max-width: 520px;
        flex-direction: column;
        justify-content: flex-start;
        align-items: flex-start;
        padding-top: 40%;
        display: flex;
        position: absolute;
        top: 0%;
        bottom: 0%;
        left: 0%;
        right: 0%;
        position: fixed;
      }

      @media screen and (min-width: 1280px) {
        .text_wrap_2 {
          display: flex;
        }
      }

      .div-block-24 {
        align-items: center;
        padding-bottom: 80px;
        display: flex;
      }

      .div-block-25 {
        flex-direction: column;
        align-items: flex-start;
        display: flex;
      }

      .text_wrap_3 {
        z-index: 3;
        height: 100%;
        max-width: 520px;
        flex-direction: column;
        justify-content: flex-start;
        align-items: flex-start;
        padding-top: 40%;
        display: flex;
        position: absolute;
        top: 0%;
        bottom: 0%;
        left: 0%;
        right: 0%;
        position: fixed;
      }
    </style>
  </head>
  <body style="height: 500vh">
    <div class="left-t">
      <div class="left_content_wrap">
        <div style="opacity: 1" class="text_wrap">
          <div class="div-block-99">
            <div class="div-block-22">
              <h2 class="heading_h1 text_home">Die Kanzlei</h2>
            </div>
            <div class="div-block-23">
              <p class="text_main">
                Herzlich willkommen bei Ihrer Steuerkanzlei Hornauer! Bei uns
                erwartet Sie, neben einem seriösen leistungsbezogenen
                Arbeitsethos, eine herzliche und kollegiale Atmosphäre, in deren
                Fokus der Mandant mit seinen Belangen und Wünschen steht.
              </p>
            </div>
          </div>
        </div>
        <div style="opacity: 0" class="text_wrap_2">
          <div class="div-block-99">
            <div class="div-block-24">
              <h2 class="heading_h1 text_home">Katrin Hornauer</h2>
            </div>
            <div class="div-block-25">
              <p class="text_main">
                Katrin Hornauer absolvierte ihr Studium der
                Betriebswirtschaftslehre an der Universität Leipzig, welches sie
                1995 als Diplom-Kauffrau abschloss. Nach Jahren in der
                betriebswirtschaftlichen Praxis legte sie 1999 die Prüfung zur
                Steuerberaterin ab. Seit Oktober 2001 führt sie erfolgreich ihre
                eigene Kanzlei in der Landeshauptstadt Magdeburg.
              </p>
            </div>
          </div>
        </div>
        <div style="opacity: 0" class="text_wrap_3">
          <div class="div-block-99">
            <div class="div-block-24">
              <h2 class="heading_h1 text_home">Unser Team</h2>
            </div>
            <div class="div-block-25">
              <p class="text_main">
                Unsere Kanzlei vereint qualifizierte und engagierte
                Steuerfachangestellte. So gewährleisten wir unseren Mandanten
                eine kompetente und individuelle Betreuung. Davon profitieren
                Sie sowohl als Unternehmen, Selbstständige, Freiberufler oder
                Privatperson, unabhängig davon, welcher Branche Sie angehören.
              </p>
            </div>
          </div>
        </div>
      </div>
    </div>

    <script>
      window.addEventListener("scroll", function () {
        let num = window.scrollY / window.innerHeight;
        let index = Math.floor(num);
        let opacity = num - index;

        // Determine the total number of text_wrap elements
        let totalElements = document.querySelectorAll(
          ".text_wrap, .text_wrap_2, .text_wrap_3"
        ).length;

        // Set the opacity of the target .text_wrap element
        document
          .querySelectorAll(".text_wrap, .text_wrap_2, .text_wrap_3")
          .forEach(function (element, i) {
            if (i === index) {
              if (i === 0) {
                // For the first text_wrap, start at opacity 1 and decrease to 0
                element.style.opacity = 1 - opacity;
              } else if (i === 1) {
                // For the second text_wrap, start at opacity 0, increase to 1, then decrease to 0
                element.style.opacity =
                  opacity < 0.5 ? 2 * opacity : 2 * (1 - opacity);
              } else {
                // For the third text_wrap, start at opacity 0 and increase to 1, maintaining 1 opacity at the end
                element.style.opacity = opacity < 0.5 ? 2 * opacity : 1;
              }
            } else if (i === totalElements - 1 && index >= totalElements - 1) {
              // For the last text_wrap, maintain opacity at 1 when scrolling out of the container
              element.style.opacity = 1;
            } else {
              element.style.opacity = 0;
            }
          });
      });
    </script>
  </body>
</html>