代码之家  ›  专栏  ›  技术社区  ›  fightstarr20

滚动时更改徽标分区背景色

  •  6
  • fightstarr20  · 技术社区  · 6 年前

    我正在尝试实现 slip-scroll parallax 类型效果使用 CSS JavaScript . 当屏幕向下滚动时,右上角的徽标将改变它的背景以与下面的对比。在左边还有一个导航按钮也可以。

    到目前为止…

    // 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>

    右边的徽标按预期运行,当您向下滚动页面时,背景会发生变化。

    然而,左边的导航系统工作不正常,我认为它需要一些偏移量添加,因为当导航系统改变时,它会改变。

    有人知道我哪里出错了吗?

    1 回复  |  直到 6 年前
        1
  •  1
  •   Temani Afif    6 年前

    考虑到您的代码,您将需要复制您的逻辑,以便使它对这两个元素都有效。您需要调整 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 这不是 well supported in older browsers .

    关于梯度,我用 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>