当您在网页上滚动时淡出一个部分并淡入下一部分

Osc*_*son 9 html javascript css

我有一个网站,我希望每个部分都占据屏幕,当您向下滚动页面时,这些部分会随着下一个部分进入视图而淡出。我正在努力思考这个数学需要如何运作。

对于一个部分来说,很容易,基本上是元素的高度和距顶部的距离来获取不透明度百分比。然而,我只是不太清楚其他部分的数学原理。我需要第 2 部分开始淡入,因为第 1 部分正在淡出。

我不想滚动。我只是想要一个滚动效果。我不想覆盖默认的滚动行为,而是想在滚动时以动画形式输入/输出,其中某个 Y 滚动值 = 某个 CSS 值,而不是某种“断点”,它会动画到新的“幻灯片”。

例如,为了获得适当的效果,我的数学将行的高度除以 2,以便它淡出 50%,因为下一部分应该淡出 50%。但是,到目前为止,数学对其他部分不起作用。

该网站使用 vanilla JS,因为它应该是一个简单的寻呼机。

下面的例子:

    (function () {
        window.addEventListener('scroll', () => {
          const rows = document.querySelectorAll('.row');

          rows.forEach(function (row, index) {
            const distanceToTop = window.pageYOffset;
            const elementHeight = row.offsetHeight * (index + 1) / 2;
            row.style.opacity = ((elementHeight - distanceToTop) / elementHeight * 100) / 100;
          });
        });
      })();
Run Code Online (Sandbox Code Playgroud)
    * {
      box-sizing: border-box;
    }

    body {
      margin: 0;
      padding: 0 0 0 0;
      font-family: sans-serif;
      font-family: 'Manrope', helvetiva, sans-serif;
      transition: background-color 1s;
      color:#fff;
      background: linear-gradient(0deg, #100521 0%, #50357c 50%, #878290 100%);
    }

    header {
      position: fixed;
      top: 0;
      width: 100%;
      background: #fff;
      z-index: 999;
    }

    header h1 {
      font-family: 'Lack';
      font-size: 4em;
      text-align: center;
      padding: 10px;
      color: #100521;
    }

    .row-container .row:first-child {
      opacity: 1;
    }

    .row {
      opacity: 0;
      height: 100vh;
      display: flex;
      flex-direction:column;
    }

    .row-inner {
      display: grid;
      grid-template-columns: 1fr 1fr;
      position: sticky;
      top: 0;
      /* border: 1px solid yellow; */
      padding: 0;
      height: 100vh;
    }

    .column {
      display: flex;
      flex-direction: column;
      justify-content: center;
      align-content: center;
      flex: 50%;
      padding: 10px;
    }

    .left-column {
      background-color: transparent;
    }

    .right-column {
      background-color: transparent;
    }

    h1 {
      font-family: 'Unbounded', helvetica, sans-serif;
    }

    h1 {
      margin: 0;
      font-size: 36px;
    }

    h2 {
      margin: 0;
      font-size: 24px;
    }

    p {
      margin: 10px 0;
      font-size: 18px;
      line-height: 1.5;
    }

    img {
      width: 100%;
      height: auto;
    }
Run Code Online (Sandbox Code Playgroud)
<!DOCTYPE html>
<html>
<head>
  <link rel="preconnect" href="https://fonts.googleapis.com"><link rel="preconnect" href="https://fonts.gstatic.com" crossorigin><link href="https://fonts.googleapis.com/css2?family=Manrope&family=Unbounded&family=Lack&display=swap" rel="stylesheet">
</head>
  <body>
    <header>
      <h1>My App</h1>
    </header>
    <!-- First row -->
    <div class="row-container">
      <div class="row section-1">
        <div class="row-inner">
          <div class="column left-column">
            <div class="column-inner">
              <h1>Headline 1</h1>
              <h2>Subhead 1</h2>
              <p>Lorem Ipsum dolar Gamet</p>
            </div>
          </div>
          <div class="column right-column">
            <div class="column-inner">
              <img src="https://avatars.dicebear.com/api/adventurer/team-member-1.jpg" alt="Image 1">
            </div>
          </div>
        </div>
      </div>

      <!-- Second row -->
      <div class="row section-2">
        <div class="row-inner">
          <div class="column left-column">
            <div class="column-inner">
              <h1>Headline 2</h1>
              <h2>Subhead 2</h2>
              <p>Lorem Ipsum dolar Gamet</p>
            </div>
          </div>
          <div class="column right-column">
            <div class="column-inner">
              <img src="https://avatars.dicebear.com/api/adventurer/team-member-2.jpg" alt="Image 2">
            </div>
          </div>
        </div>
      </div>

      <!-- Third row -->
      <div class="row section-3">
        <div class="row-inner">
          <div class="column left-column">
            <div class="column-inner">
              <h1>Headline 3</h1>
              <h2>Subhead 3</h2>
              <p>Lorem Ipsum dolar Gamet</p>
            </div>
          </div>
          <div class="column right-column">
            <div class="column-inner">
              <img src="https://avatars.dicebear.com/api/adventurer/team-member-3.jpg" alt="Image 3">
            </div>
          </div>
        </div>
      </div>

      <!-- Fourth row -->
      <div class="row section-4">
        <div class="row-inner">
          <div class="column left-column">
            <div class="column-inner">
              <h1>Headline 4</h1>
              <h2>Subhead 4</h2>
              <p>Lorem Ipsum dolar Gamet</p>
            </div>
          </div>
          <div class="column right-column">
            <div class="column-inner">
              <img src="https://avatars.dicebear.com/api/adventurer/team-member-4.jpg" alt="Image 4">
            </div>
          </div>
        </div>
      </div>
    </div>
  </body>
</html>
Run Code Online (Sandbox Code Playgroud)

Hom*_*ice 1

你并没有真正要求一个网络组件,我只是得意忘形了。这是一个有趣的挑战!无论如何,这是一个不是 Web 组件的版本。我还意识到我错过了您提供的所有 css。所以我也添加了这一点。我不确定稍微调整一下 css 是否是禁止的……但我做到了。我还添加了一个 [section] 标签,它包含除应用程序标头之外的所有内容,以使其更加防弹...请告诉我是否需要完全按照您发布的方式使用您的代码。

我很难找到既能在大屏幕和手机上提供足够戏剧性的效果又不会出现一些丑陋的黑客的设置,所以我选择了妥协。您可以通过更改 IntersectionObserver 的 rootMargin 选项来针对大或小进行优化。较小的值会使淡入淡出效果更加显着,但值太小会导致内容在较小的设备上看起来褪色。当我发布此内容时,rootMargin 设置为“-25px”。显然你可以使用负值,但据我所知,你只能使用“px”作为测量值。其他测量似乎不起作用。

呜呜……

我使用 IntersectionObserver

const observer = new IntersectionObserver(fadeInOut, options);
Run Code Online (Sandbox Code Playgroud)

IntersectionObserver 采用的选项之一称为“阈值”。我不太明白,但是 MDN 建议如果你想轮询视口来确定元素可见性,你应该将“threshold”的值设置为一个数组,其中包含许多从 0 到 1 的数字。该示例提供了一个函数生成了 20 个,所以这就是我使用的。

function buildThresholds() {
  const steps = 20;
  const thresholds = [];

  for (let i = 0; i <= steps; i++) {
      let ratio = i/steps;
      thresholds.push(ratio);
   }

    thresholds.push(0);
    return thresholds;
  }
Run Code Online (Sandbox Code Playgroud)

然后我使用 querySelectorAll(".row-container") 获取要观看的元素集合。

然后我循环遍历这些元素并将每个元素添加到观察者的监视列表中。

observer.observe(elem);
Run Code Online (Sandbox Code Playgroud)

然后,在创建 IntersectionObserver 的新实例时提供的回调中,我将每个元素的不透明度设置为 intersectionRatio,这是由传递给回调的 IntersectionObserverEntry 实例提供的属性。

function fadeInOut(items, observer) {
  items.forEach( (item) => {
      item.target.style.opacity = item.intersectionRatio;
  });
}
Run Code Online (Sandbox Code Playgroud)

const observer = new IntersectionObserver(fadeInOut, options);
Run Code Online (Sandbox Code Playgroud)
function buildThresholds() {
  const steps = 20;
  const thresholds = [];

  for (let i = 0; i <= steps; i++) {
      let ratio = i/steps;
      thresholds.push(ratio);
   }

    thresholds.push(0);
    return thresholds;
  }
Run Code Online (Sandbox Code Playgroud)
observer.observe(elem);
Run Code Online (Sandbox Code Playgroud)