随着滚动更改标志div的背景颜色

6
我正在尝试使用CSS和JavaScript实现滑动滚动视差效果,这种效果被称为“slip-scroll parallax”。当屏幕向下滚动时,右上角的徽标将更改其背景颜色以与下方形成对比。左侧还有一个导航按钮也会做同样的事情。
目前我已经实现了以下内容...

// Detect request animation frame
var scroll = window.requestAnimationFrame ||
  window.webkitRequestAnimationFrame ||
  window.mozRequestAnimationFrame ||
  window.msRequestAnimationFrame ||
  window.oRequestAnimationFrame
  // IE Fallback, you can even fallback to onscroll
  ||
  function(callback) {
    window.setTimeout(callback, 1000 / 60)
  };
var lastPosition = -1;

// my Variables
var lastSection = false;
var replaceItemTop = -1;
var replaceItemBottom = -1;
var replaceItemHeight = -1;

// The Scroll Function
function loop() {
  var top = window.pageYOffset;
  // my variables

  // my sections to calculate stuff
  var sections = document.querySelectorAll('.section');
  var replaceContainer = document.querySelectorAll('.js-replace');
  var replaceItem = document.querySelectorAll('.js-replace__item');

  if (replaceItem.length > 0) {
    // get top position of item from container, because image might not have loaded
    replaceItemTop = parseInt(replaceContainer[0].getBoundingClientRect().top);
    replaceItemHeight = replaceItem[0].offsetHeight;
    replaceItemBottom = replaceItemTop + replaceItemHeight;
  }

  var sectionTop = -1;
  var sectionBottom = -1;
  var currentSection = -1;

  // Fire when needed
  if (lastPosition == window.pageYOffset) {
    scroll(loop);
    return false;
  } else {
    lastPosition = window.pageYOffset;

    // Your Function
    Array.prototype.forEach.call(sections, function(el, i) {
      sectionTop = parseInt(el.getBoundingClientRect().top);
      sectionBottom = parseInt(el.getBoundingClientRect().bottom);

      // active section
      if ((sectionTop <= replaceItemBottom) && (sectionBottom > replaceItemTop)) {
        // check if current section has bg
        currentSection = el.classList.contains('section--bg');

        // switch class depending on background image
        if (currentSection) {
          replaceContainer[0].classList.remove('js-replace--reverse');
        } else {
          replaceContainer[0].classList.add('js-replace--reverse')
        }
      }
      // end active section

      // if active Section hits replace area
      if ((replaceItemTop < sectionTop) && (sectionTop <= replaceItemBottom)) {
        // animate only, if section background changed
        if (currentSection != lastSection) {
          document.documentElement.style.setProperty('--replace-offset', 100 / replaceItemHeight * parseInt(sectionTop - replaceItemTop) + '%');
        }
      }
      // end active section in replace area

      // if section above replace area
      if (replaceItemTop >= sectionTop) {
        // set offset to 0 if you scroll too fast
        document.documentElement.style.setProperty('--replace-offset', 0 + '%');
        // set last section to current section
        lastSection = currentSection;
      }

    });

  }

  // Recall the loop
  scroll(loop)
}

// Call the loop for the first time
loop();

window.onresize = function(event) {
  loop();
};
/* variables */

:root {
  /* this value is going to be changed by javascript */
  --replace-offset: 50%;
  --replace-offset-2: calc((100% - var(--replace-offset)) * -1)
}

a {
  text-decoration: none;
}


/* set image position */

img {
  vertical-align: bottom;
}

.footer {
  background-color: black;
  color: white;
  padding-top: 50px;
  padding-bottom: 50px;
  text-align: center;
}


/* without fixed header this makes no sense */

.header {
  position: fixed;
  top: 0;
  right: 0;
  z-index: 9;
}

.header_nav {
  position: fixed;
  top: 50%;
  transform: translateY(-50%);
  left: 0;
  z-index: 9;
}

.logo {
  background-color: white;
  display: inline-block;
  border: solid;
  padding: 10px;
  border-radius: 10px;
  font-size: 2em;
}

.logo a {
  color: black;
}

.logo--invert {
  background-color: black;
  color: white;
  border-color: white;
}

.logo--invert a {
  color: white;
}

.sidelogo {
  background-color: white;
  display: inline-block;
  border: solid;
  padding: 10px;
  border-radius: 10px;
  font-size: 2em;
}

.sidelogo a {
  color: black;
}

.sidelogo--invert {
  background-color: black;
  color: white;
  border-color: white;
}

.sidelogo--invert a {
  color: white;
}

.section {
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  justify-content: center;
  text-align: center;
}

section--1 {
  height: 100vh;
  width: 100%;
}

.hero {
  position: absolute;
  top: 0;
  left: 0;
  height: 100%;
  width: 100%;
  background-image: linear-gradient(rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 0.5)), url("https://www.w3schools.com/howto/photographer.jpg");
  background-position: center;
  background-repeat: no-repeat;
  background-size: cover;
}

.section--2 {
  background: white;
}

.section--3 {
  background: black;
  color: white;
}


/**
  This is the interesting part
**/


/* align content above each other without absolute */

.js-replace {
  display: grid;
}

.js-replace__item {
  grid-row: -1 / 1;
  grid-column: -1 / 1;
  overflow: hidden;
  will-change: transform;
}


/* item to replace with */

.js-replace__item {
  transform: translateY(calc(var(--replace-offset) * 1));
}

.js-replace__content {
  /* fixes problem with calculating correct height in js */
  border: 1px solid transparent;
  will-change: transform;
  transform: translateY(calc(var(--replace-offset) * -1));
}


/* previous replace item*/

.js-replace__item--active {
  transform: translateY(calc(var(--replace-offset-2) * 1));
}

.js-replace__item--active .js-replace__content {
  transform: translateY(calc(var(--replace-offset-2) * -1));
}


/* REVERSE ANIMATION */

.js-replace--reverse .js-replace__item {
  transform: translateY(calc(var(--replace-offset-2) * 1));
}

.js-replace--reverse .js-replace__content {
  transform: translateY(calc(var(--replace-offset-2) * -1));
}


/* previous replace item*/

.js-replace--reverse .js-replace__item--active {
  transform: translateY(calc(var(--replace-offset) * 1));
}

.js-replace--reverse .js-replace__item--active .js-replace__content {
  transform: translateY(calc(var(--replace-offset) * -1));
}
<body class="body">

  <div class="header">

    <!-- replace content -->
    <div class="header__logo js-replace">

      <!-- item to replace -->
      <div class="js-replace__item  js-replace__item--active">
        <div class="js-replace__content">
          <div class="logo"><a href="#">Logo</a></div>
        </div>
      </div>
      <!-- end item to replace -->

      <!-- item to replace with -->
      <div class="js-replace__item">
        <div class="js-replace__content">
          <div class="logo logo--invert"><a href="#">Logo</a></div>
        </div>
      </div>
      <!-- end item to replace with -->

    </div>
    <!-- end replace content -->

  </div>

  <div class="header_nav">

    <!-- replace content -->
    <div class="header__side js-replace">

      <!-- item to replace -->
      <div class="js-replace__item  js-replace__item--active">
        <div class="js-replace__content">
          <div class="sidelogo"><a href="#">Nav</a></div>
        </div>
      </div>
      <!-- end item to replace -->

      <!-- item to replace with -->
      <div class="js-replace__item">
        <div class="js-replace__content">
          <div class="sidelogo sidelogo--invert"><a href="#">Nav</a></div>
        </div>
      </div>
      <!-- end item to replace with -->

    </div>
    <!-- end replace content -->

  </div>

  <main class="main">

    <section class="section--1 section">
      <div class="hero">
      </div>
    </section>

    <section class="section--2 section section--bg">
      <h1>Section 2</h1>
      <p>Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vestibulum tortor quam, feugiat vitae, ultricies eget, tempor sit amet, ante. Donec eu libero sit amet quam egestas semper. Aenean ultricies mi vitae est.
        Mauris placerat eleifend leo. Quisque sit amet est et sapien ullamcorper pharetra. Vestibulum erat wisi, condimentum sed, commodo vitae, ornare sit amet, wisi. Aenean fermentum, elit eget tincidunt condimentum, eros ipsum rutrum orci, sagittis
        tempus lacus enim ac dui. Donec non enim in turpis pulvinar facilisis. Ut felis. Praesent dapibus, neque id cursus faucibus, tortor neque egestas augue, eu vulputate magna eros eu erat. Aliquam erat volutpat. Nam dui mi, tincidunt quis, accumsan
        porttitor, facilisis luctus, metus</p>
      <p>Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vestibulum tortor quam, feugiat vitae, ultricies eget, tempor sit amet, ante. Donec eu libero sit amet quam egestas semper. Aenean ultricies mi vitae est.
        Mauris placerat eleifend leo.</p>
    </section>

    <section class="section--3  section">
      <h1>Section 3</h1>
      <p>
        <strong>Pellentesque habitant morbi tristique</strong> senectus et netus et malesuada fames ac turpis egestas. Vestibulum tortor quam, feugiat vitae, ultricies eget, tempor sit amet, ante. Donec eu libero sit amet quam egestas semper. <em>Aenean ultricies mi vitae est.</em>        Mauris placerat eleifend leo. Quisque sit amet est et sapien ullamcorper pharetra. Vestibulum erat wisi, condimentum sed, <code>commodo vitae</code>, ornare sit amet, wisi. Aenean fermentum, elit eget tincidunt condimentum, eros ipsum rutrum orci,
        sagittis tempus lacus enim ac dui. <a href="#">Donec non enim</a> in turpis pulvinar facilisis. Ut felis.
      </p>
      <h2>Header Level 2</h2>
      <ol>
        <li>Lorem ipsum dolor sit amet, consectetuer adipiscing elit.</li>
        <li>Aliquam tincidunt mauris eu risus.</li>
      </ol>
      <blockquote>
        <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus magna. Cras in mi at felis aliquet congue. Ut a est eget ligula molestie gravida. Curabitur massa. Donec eleifend, libero at sagittis mollis, tellus est malesuada tellus, at luctus
          turpis elit sit amet quam. Vivamus pretium ornare est.</p>
      </blockquote>
      <h3>Header Level 3</h3>
      <ul>
        <li>Lorem ipsum dolor sit amet, consectetuer adipiscing elit.</li>
        <li>Aliquam tincidunt mauris eu risus.</li>
      </ul>
    </section>

    <section class="section--4 section  section--bg">
      <h1>Section 4</h1>
      <p>
        Some great section 4 content
      </p>
      <ul>
        <li>This is a list item</li>
        <li>This is a list item</li>
        <li>This is a list item</li>
        <li>This is a list item</li>
        <li>This is a list item</li>
      </ul>
    </section>

    <section class="section--5 section section--bg">
      <h1 class="section__title">
        Section 5
      </h1>
      <p>
        This is some random content for section 5
      </p>
    </section>

  </main>

  <footer class="footer section">

    <form action="#" method="post">
      <div>
        <label for="name">Text Input:</label>
        <input type="text" name="name" id="name" value="" tabindex="1" />
      </div>
      <div>
        <h4>Radio Button Choice</h4>
        <label for="radio-choice-1">Choice 1</label>
        <input type="radio" name="radio-choice-1" id="radio-choice-1" tabindex="2" value="choice-1" />
        <label for="radio-choice-2">Choice 2</label>
        <input type="radio" name="radio-choice-2" id="radio-choice-2" tabindex="3" value="choice-2" />
      </div>
      <div>
        <label for="select-choice">Select Dropdown Choice:</label>
        <select name="select-choice" id="select-choice">
          <option value="Choice 1">Choice 1</option>
          <option value="Choice 2">Choice 2</option>
          <option value="Choice 3">Choice 3</option>
        </select>
      </div>
      <div>
        <label for="textarea">Textarea:</label>
        <textarea cols="40" rows="8" name="textarea" id="textarea"></textarea>
      </div>
      <div>
        <label for="checkbox">Checkbox:</label>
        <input type="checkbox" name="checkbox" id="checkbox" />
      </div>
      <div>
        <input type="submit" value="Submit" />
      </div>
    </form>

  </footer>

</body>

右侧的Logo表现正常,当您向下滚动页面时,背景会发生变化。

然而,左侧的导航栏没有正确工作,我认为它需要添加一些偏移量,因为当前它会随着导航栏的更改而更改。

有任何想法是我在哪里出错了吗?


1
@duplicate_closure 请仔细阅读问题。 - Temani Afif
1个回答

1

考虑到您的代码,您需要复制逻辑,以使其适用于两个元素。您需要调整第二个元素的top变量,使其不再是屏幕顶部,而是屏幕顶部加上元素的偏移量。

这里有另一个想法,更多地依赖于CSS,少量JS代码就可以获得几乎相同的结果:

window.onscroll = function() {
  var scroll = window.scrollY || window.scrollTop || document.getElementsByTagName("html")[0].scrollTop;
  document.documentElement.style.setProperty('--scroll-var', scroll+"px");
}
:root {
  --scroll-var: 0px;
}


a {
  text-decoration: none;
}


/* set image position */

img {
  vertical-align: bottom;
}

.footer {
  background-color: #fff;
  color: #000;
  padding-top: 50px;
  padding-bottom: 50px;
  text-align: center;
}


/* without fixed header this makes no sense */

.header {
  position: fixed;
  top: 0;
  right: 0;
  z-index: 9;
}

.header_nav {
  position: fixed;
  top: 50%;
  transform: translateY(-50%);
  left: 0;
  z-index: 9;
}

.logo,
.sidelogo{
  background:
    repeating-linear-gradient(to bottom,
        #fff 0,#fff 100vh,
        #000 100vh,#000 200vh) top/100% 600vh no-repeat padding-box,
     repeating-linear-gradient(to bottom,
        #000 0,#000 100vh,
        #fff 100vh,#fff 200vh) top/100% 600vh no-repeat border-box;
  display: inline-block;
  border: solid transparent;
  border-radius: 10px;
  font-size: 2em;
}
.logo a,
.sidelogo a{
  display:block;
  padding: 10px;
  background:
    repeating-linear-gradient(to bottom,
        #000 0,#000 100vh,
        #fff 100vh,#fff 200vh) top/100% 600vh no-repeat;
  background-clip: text;
  color: transparent;
  -webkit-background-clip: text;
  -webkit-text-fill-color: transparent;
}

.logo,
.logo a{
  background-position:0 calc(-1 * var(--scroll-var));
}
.sidelogo,
.sidelogo a{
  background-position:0 calc(-1 * var(--scroll-var) - 50vh + 30px);
}



.section {
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  justify-content: center;
  text-align: center;
}

section--1 {
  height: 100vh;
  width: 100%;
}

.hero {
  position: absolute;
  top: 0;
  left: 0;
  height: 100%;
  width: 100%;
  background-image: linear-gradient(rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 0.5)), url("https://www.w3schools.com/howto/photographer.jpg");
  background-position: center;
  background-repeat: no-repeat;
  background-size: cover;
}

.section--2,
.footer{
  background: white;
}

.section--3,
.section--5{
  background: black;
  color: white;
}
<body class="body">

  <div class="header">
    <div class="logo"><a href="#">Logo</a></div>

  </div>

  <div class="header_nav">

          <div class="sidelogo"><a href="#">Nav</a></div>

  </div>

  <main class="main">

    <section class="section--1 section">
      <div class="hero">
      </div>
    </section>

    <section class="section--2 section section--bg">
      <h1>Section 2</h1>
      <p>Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vestibulum tortor quam, feugiat vitae, ultricies eget, tempor sit amet, ante. Donec eu libero sit amet quam egestas semper. Aenean ultricies mi vitae est.
        Mauris placerat eleifend leo. Quisque sit amet est et sapien ullamcorper pharetra. Vestibulum erat wisi, condimentum sed, commodo vitae, ornare sit amet, wisi. Aenean fermentum, elit eget tincidunt condimentum, eros ipsum rutrum orci, sagittis
        </p>
    </section>

    <section class="section--3  section">
      <h1>Section 3</h1>
      <p>
        <strong>Pellentesque habitant morbi tristique</strong> senectus et netus et malesuada fames ac turpis egestas. Vestibulum tortor quam, feugiat vitae, ultricies eget, tempor sit amet, ante. Donec eu libero sit amet quam egestas semper. <em>Aenean ultricies mi vitae est.</em>        Mauris placerat eleifend leo. Quisque sit amet est et sapien ullamcorper pharetra. Vestibulum erat wisi, condimentum sed, <code>commodo vitae</code>, ornare sit amet, wisi. Aenean fermentum, elit eget tincidunt condimentum, eros ipsum rutrum orci,
        sagittis tempus lacus enim ac dui. <a href="#">Donec non enim</a> in turpis pulvinar facilisis. Ut felis.
      </p>
      <h2>Header Level 2</h2>
      <ol>
        <li>Lorem ipsum dolor sit amet, consectetuer adipiscing elit.</li>
        <li>Aliquam tincidunt mauris eu risus.</li>
      </ol>
    </section>

    <section class="section--4 section  section--bg">
      <h1>Section 4</h1>
      <p>
        Some great section 4 content
      </p>
      <ul>
        <li>This is a list item</li>
        <li>This is a list item</li>
        <li>This is a list item</li>
        <li>This is a list item</li>
        <li>This is a list item</li>
      </ul>
    </section>

    <section class="section--5 section section--bg">
      <h1 class="section__title">
        Section 5
      </h1>
      <p>
        This is some random content for section 5
      </p>
    </section>

  </main>

  <footer class="footer section">

    <form action="#" method="post">
      <div>
        <label for="name">Text Input:</label>
        <input type="text" name="name" id="name" value="" tabindex="1" />
      </div>
      <div>
        <h4>Radio Button Choice</h4>
        <label for="radio-choice-1">Choice 1</label>
        <input type="radio" name="radio-choice-1" id="radio-choice-1" tabindex="2" value="choice-1" />
        <label for="radio-choice-2">Choice 2</label>
        <input type="radio" name="radio-choice-2" id="radio-choice-2" tabindex="3" value="choice-2" />
      </div>
      <div>
        <label for="select-choice">Select Dropdown Choice:</label>
        <select name="select-choice" id="select-choice">
          <option value="Choice 1">Choice 1</option>
          <option value="Choice 2">Choice 2</option>
          <option value="Choice 3">Choice 3</option>
        </select>
      </div>
      <div>
        <label for="textarea">Textarea:</label>
        <textarea cols="40" rows="8" name="textarea" id="textarea"></textarea>
      </div>
      <div>
        <label for="checkbox">Checkbox:</label>
        <input type="checkbox" name="checkbox" id="checkbox" />
      </div>
      <div>
        <input type="submit" value="Submit" />
      </div>
    </form>

  </footer>

</body>

关键在于使用渐变色为您的元素提供色彩。颜色应该是站点颜色的相反色。我们的部分是100vh高度交替白色/黑色,因此我们使用黑/白渐变,每个100vh更改一次,并覆盖整个屏幕(在这种情况下为600vh,因为我们有6个部分)。
然后,我们使用一个简单的CSS变量,在滚动时更新它来定义背景位置。就像我们让背景在元素内滑动一样,这样它就相对于整个文档保持固定,我们将获得所需的结果。
这种方法的缺点:
  • 部分需要具有固定的高度,这就是为什么我稍微调整内容以不超过100vh以正确定义渐变的原因。如果部分是动态的,我们可以考虑使用更多的CSS变量来调整渐变。
  • 我使用背景来着色文本,使用background-clip:text,在旧浏览器中支持不
关于渐变,我使用了repeating-linear-gradient,因为我调整了部分使得白色和黑色完美交替,但如果没有这种情况,我们可以考虑使用linear-gradient,在其中定义每个部分的颜色。

这里是一个更通用的例子(我删除了边框着色的渐变,以使其更容易)

window.onscroll = function() {
  var scroll = window.scrollY || window.scrollTop || document.getElementsByTagName("html")[0].scrollTop;
  document.documentElement.style.setProperty('--scroll-var', scroll + "px");
}
:root {
  --scroll-var: 0px;
}

body {
 margin:0;
}

.header {
  position: fixed;
  top: 0;
  right: 0;
  z-index: 9;
}

.header_nav {
  position: fixed;
  top: 50%;
  transform: translateY(-50%);
  left: 0;
  z-index: 9;
}

.logo,
.sidelogo {
  background: 
   linear-gradient(to bottom, 
    #fff 0, #fff 100vh, 
    blue 100vh, blue 300vh,
    red 300vh, red 400vh,
    #fff 400vh, #fff 500vh,
    #000 500vh, #000 600vh) 
    top/100% 600vh;
  display: inline-block;
  border: solid transparent;
  border-radius: 10px;
  font-size: 2em;
}

.logo a,
.sidelogo a {
  display: block;
  padding: 10px;
  background:
    linear-gradient(to bottom, 
      #000 0, #000 100vh, 
      red 100vh, red 300vh,
      blue 300vh, blue 400vh,
      #000 400vh, #000 500vh,
      #fff 500vh, #fff 600vh)
      top/100% 600vh no-repeat;
  background-clip: text;
  color: transparent;
  -webkit-background-clip: text;
  -webkit-text-fill-color: transparent;
}

.logo,
.logo a {
  background-position: 0 calc(-1 * var(--scroll-var));
}

.sidelogo,
.sidelogo a {
  background-position: 0 calc(-1 * var(--scroll-var) - 50vh + 30px);
}

.section {
  min-height: 100vh;
}


.hero {
  position: absolute;
  top: 0;
  left: 0;
  height: 100%;
  width: 100%;
  background-image: linear-gradient(rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 0.5)), url("https://www.w3schools.com/howto/photographer.jpg");
  background-position: center;
  background-repeat: no-repeat;
  background-size: cover;
}
<div class="header">
    <div class="logo"><a href="#">Logo</a></div>

  </div>

  <div class="header_nav">

    <div class="sidelogo"><a href="#">Nav</a></div>

  </div>


    <section class="section">
      <div class="hero">
      </div>
    </section>

    <section class="section" style="background:red;">

    </section>

    <section class="section" style="background:red;">

    </section>

    <section class="section" style="background:blue;">

    </section>

    <section class="section" style="background:#000;">

    </section>
    <section class="section" style="background:#fff;">

    </section>


谢谢您抽出时间做这件事,我将进一步阅读您的每个建议。 - fightstarr20

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接