【问题标题】:GSAP: Pin progress bar when it hits element + progress bar not accrateGSAP:当它击中元素时固定进度条+进度条不准确
【发布时间】:2022-01-25 14:33:36
【问题描述】:

我正在尝试创建一个进度条,以显示用户仍有多少特定元素可以查看。以下是一些细节:

  • .postProgressBar 默认出现在.postHeroImage
  • 当用户滚动时,我希望 .postProgressBar 可以根据 .spacer 元素的剩余滚动量慢慢填满。
  • .postProgressBar 到达header 的底部时,我希望它变为fixedheader 的底部(并在.postHeroImage 再次出现时取消修复)。

看看我目前的做法:

$(function() {

gsap.registerPlugin(ScrollTrigger);

  $(window).scroll(function() {
    var scroll = $(window).scrollTop();
    if (scroll >= 1) {
      $(".header").addClass("fixed");
    } else {
      $(".header").removeClass("fixed");
    }
  });
  
    var action = gsap.set('.postProgressBar', { position:'fixed', paused:true});

  gsap.to('progress', {
    value: 100,
    ease: 'none',
    scrollTrigger: {
      trigger: "#startProgressBar",
      scrub: 0.3,
      markers:true,
      onEnter: () => action.play(),
      onLeave: () => action.reverse(),
      onLeaveBack: () => action.reverse(),
      onEnterBack: () => action.reverse(),
    }
  });

});
body {
  background-color: lightblue;
  --white: #FFFFFF;
  --grey: #002A54;
  --purple: #5D209F;
}

.header {
  position: absolute;
  top: 0;
  width: 100%;
  padding: 20px 15px;
  z-index: 9999;
  background-color: var(--white);
}
.header.fixed {
  position: fixed;
  background-color: var(--white);
  border-bottom: 1px solid var(--grey);
}

.postHeroImage {
  padding: 134px 0 0 0;
  margin-bottom: 105px;
  position: relative;
}
.postHeroImage__bg {
  background-size: cover;
  background-repeat: no-repeat;
  width: 100%;
  min-height: 400px;
}

progress {
  position: absolute;
  bottom: -15px;
  left: 0;
  -webkit-appearance: none;
  appearance: none;
  width: 100%;
  height: 15px;
  border: none;
  background: transparent;
  z-index: 9999;
}

progress::-webkit-progress-bar {
  background: transparent;
}

progress::-webkit-progress-value {
  background: var(--purple);
  background-attachment: fixed;
}

progress::-moz-progress-bar {
  background: var(--purple);
  background-attachment: fixed;
}

.spacer {
  height: 1000vh;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.9.0/gsap.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.9.0/ScrollTrigger.min.js"></script>

<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet">


<body>

  <header class="header">Header</header>

  <section class="postHeroImage" id="startProgressBar">

    <progress class="postProgressBar" max="100" value="0"></progress>

    <div class="container">
      <div class="row">
        <div class="col-12">
          <div class="postHeroImage__bg" style="background-image: url( 'https://picsum.photos/200/300' );" loading="lazy"></div>
        </div>
      </div>
    </div>
  </section>

  <div class="spacer">lorum ipsum</div>

</body>

当前问题:

  1. .postProgressBar 不会变成 fixed(在检查模式下看不到 fixed 内联样式)
  2. .postProgressBar 显示的进度不准确,这取决于 .spacer 的剩余滚动量。

【问题讨论】:

    标签: javascript jquery css gsap scrolltrigger


    【解决方案1】:

    您可以简单地使用 HTML 标记 &lt;progress&gt; 代替您使用的库(您的库使用的是相同的)。

    这是一个简单的方法:

    const scrollHeight = Math.max(
      document.body.scrollHeight, document.documentElement.scrollHeight,
      document.body.offsetHeight, document.documentElement.offsetHeight,
      document.body.clientHeight, document.documentElement.clientHeight
    );
    
    window.addEventListener('scroll', (e) => document.querySelector('progress').value = window.pageYOffset / (scrollHeight - window.innerHeight) * 100)
    html, body {
      padding: 0;
      margin: 0;
      height: 2500px;
    }
    
    progress {
      position: fixed;
      border-radius: 0;
      width: 100%;
      height: 22px;
    }
    
    progress::-webkit-progress-value {
      background-color: #5D209F;
    }
    &lt;progress value="0" max="100"&gt;&lt;/progress&gt;

    用户每次滚动页面,进度都会得到一个值,即当前高度位置 / (文档的高度 - 活动屏幕高度) * 100。

    【讨论】:

      【解决方案2】:
      1. 位置sticky 在这里非常有用。您可以将它用于标题以及进度条。不费吹灰之力就能将元素固定在顶部。
      2. 要获得准确的位置,您需要使用scrollTriggerstartend 属性。这将告诉 gsap 何时开始动画以及何时结束。最后,我们需要将标题的高度 64px 添加到滚动中,因为我们的容器在视口顶部下方 64px 处。
        演示:

      $(function() {
        //read the css variable
        let bodyStyles = window.getComputedStyle(document.body);
        let headerHeight = bodyStyles.getPropertyValue('--header-height'); 
      
        gsap.registerPlugin(ScrollTrigger);
        gsap.to('progress', {
          value: 100,
          ease: 'none',
          scrollTrigger: {
            trigger: "#startProgressBar",
            scrub: 0.3,
            start: 'start 0px',
            end: 'bottom' + headerHeight,
            markers: true,
          }
        });
      });
      body {
        background-color: lightblue;
        --white: wheat;
        --grey: #002A54;
        --purple: #5D209F;
        /* 40px padding top and bottom + 24px line height*/
        --header-height: 64px;
      }
      
      .header {
        /* position: absolute;*/
        position: sticky;
        top: 0;
        width: 100%;
        padding: 20px 15px;
        z-index: 9999;
        background-color: var(--white);
      }
      
      .postHeroImage {
        padding: 134px 0 0 0;
        margin-bottom: 105px;
        position: relative;
      }
      
      .postHeroImage__bg {
        background-size: cover;
        background-repeat: no-repeat;
        width: 100%;
        min-height: 400px;
      }
      
      progress {
        position: sticky;
        top: var(--header-height);
        left: 0;
        -webkit-appearance: none;
        appearance: none;
        width: 100%;
        height: 15px;
        border: none;
        background: transparent;
        /*z-index: 9999;*/
      }
      
      progress::-webkit-progress-bar {
        background: transparent;
      }
      
      progress::-webkit-progress-value {
        background: var(--purple);
        background-attachment: fixed;
      }
      
      progress::-moz-progress-bar {
        background: var(--purple);
        background-attachment: fixed;
      }
      
      .spacer {
        height: 1000vh;
      }
      <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
      <script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.9.0/gsap.min.js"></script>
      <script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.9.0/ScrollTrigger.min.js"></script>
      <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet">
      
      
      <header class="header">Header</header>
      <section class="postHeroImage" id="startProgressBar">
        <progress class="postProgressBar" max="100" value="0"></progress>
        <div class="container">
          <div class="row">
            <div class="col-12">
              <div class="postHeroImage__bg" style="background-image: url( 'https://picsum.photos/id/705/300/200' );" loading="lazy"></div>
            </div>
          </div>
        </div>
      </section>
      
      <div class="spacer">lorum ipsum</div>

      您可以使用 start 和 end 属性。如果您只想跟踪内容的进度,请将 trigger 更改为 '.container'

      无粘性解决方案 这里我使用了固定位置:

      $(function() {
        //read the css variable
        let bodyStyles = window.getComputedStyle(document.body);
        let headerHeight = bodyStyles.getPropertyValue('--header-height');
      
        gsap.registerPlugin(ScrollTrigger);
      
        var action = gsap.set('.postProgressBar', {
          position: 'fixed',
          paused: true
        });
      
        ScrollTrigger.create({
          trigger: '.postProgressBar',
          start: 'top 64px',
          onEnter: () => action.play(),
          onLeaveBack: () => action.reverse(),
        });
      
        gsap.to('progress', {
          value: 100,
          ease: 'none',
          scrollTrigger: {
            trigger: "#mainContent",
            scrub: 0.3,
            end: 'bottom 110%',
            markers: false,
          }
        });
      });
      * {
        margin: 0;
        padding: 0;
      }
      
      body {
        background-color: lightblue;
        --white: wheat;
        --grey: #002A54;
        --purple: #5D209F;
        /* 40px padding top and bottom + 24px line height*/
        --header-height: 64px;
        position: relative;
        height:100%
      }
      
      .header {
        position: fixed;
        top: 0;
        width: 100%;
        padding: 20px 15px;
        z-index: 9999;
        background-color: var(--white);
      }
      
      .postHeroImage {
        padding: 134px 0 0 0;
        margin-bottom: 105px;
        position: relative;
        margin-top: var(--header-height);
      }
      
      .postHeroImage__bg {
        background-size: cover;
        background-repeat: no-repeat;
        width: 100%;
        min-height: 400px;
      }
      
      progress {
        position: static;
        top: var(--header-height);
        left: 0px;
        -webkit-appearance: none;
        appearance: none;
        width: 100%;
        height: 15px;
        border: none;
        background: transparent;
        /*z-index: 9999;*/
      }
      
      progress::-webkit-progress-bar {
        background: transparent;
      }
      
      progress::-webkit-progress-value {
        background: var(--purple);
        background-attachment: fixed;
      }
      
      progress::-moz-progress-bar {
        background: var(--purple);
        background-attachment: fixed;
      }
      
      .spacer {
        height: 1000vh;
      }
      <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
      <script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.9.0/gsap.min.js"></script>
      <script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.9.0/ScrollTrigger.min.js"></script>
      <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet">
      
      
      <header class="header">Header</header>
      <section class="postHeroImage" id="startProgressBar">
        <div class="container">
          <div class="row">
            <div class="col-12">
              <div class="postHeroImage__bg" style="background-image: url( 'https://picsum.photos/id/705/300/200' );" loading="lazy"></div>
            </div>
          </div>
        </div>
        <progress class="postProgressBar" max="100" value="0"></progress>
      </section>
      
      <div id="mainContent" class="spacer">lorum ipsum</div>

      【讨论】:

      • 嗨,没有sticky,有没有办法做到这一点?我这样说是因为如果任何父容器有overflow: hiddensticky 就不起作用,我的构建就是这种情况。此外,我需要默认情况下将进度条显示在图像下方,然后,当它到达header 的底部时,我希望它固定在header 下方
      • 我添加了没有粘性的解决方案。使用原位固定动作。
      • 您好,我正在尝试让进度条指示页面还有多少需要滚动。例如,在您的演示中,滚动条在点击.spacer div 时已经完成。还有很多页面要滚动,栏应该指出。此外,进度条被隐藏了一段时间,然后得到修复。是否可以在滚动(平滑)时修复它?请参阅此网站进行演示:magneticcreative.com/journal/hubl-templating-hubspot-cms
      • 我认为进步是为了形象。我已经更新了答案中的第二个 sn-p。
      猜你喜欢
      • 2020-08-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-10-05
      • 1970-01-01
      • 2014-04-30
      • 1970-01-01
      相关资源
      最近更新 更多