GSAP:点击元素时固定进度条+进度条不准确

GSAP: Pin progress bar when it hits element + progress bar not accrate

我正在尝试创建一个进度条,显示用户还有多少特定元素需要查看。以下是一些详细信息:

查看我目前的做法:

$(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 的滚动量不准确。

您可以简单地使用 HTML 标记 <progress>(您的库使用的是相同的)而不是您使用的库。

这里有一个简单的方法:

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;
}
<progress value="0" max="100"></progress>

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

  1. 位置sticky在这里很有用。您可以将它用于 header 以及进度条。它会毫不费力地将元素固定在顶部。
  2. 要获得准确的位置,您需要使用 scrollTriggerstartend 属性。这将告诉 gsap 何时开始动画以及何时结束。最后,我们需要将 header 的高度 64px 添加到滚动 cos 中,因为我们的容器距离视口顶部下方 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>

您可以使用开始和结束属性。如果您只想跟踪内容的进度,请将 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>