GSAP:点击元素时固定进度条+进度条不准确
GSAP: Pin progress bar when it hits element + progress bar not accrate
我正在尝试创建一个进度条,显示用户还有多少特定元素需要查看。以下是一些详细信息:
.postProgressBar
默认出现在.postHeroImage
下
- 当用户滚动时,我希望
.postProgressBar
根据 .spacer
元素剩余的滚动量慢慢填充。
- 当
.postProgressBar
到达我的 header
的底部时,我希望它变成 fixed
到达 header
的底部(并在 .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>
当前问题:
.postProgressBar
不会变成 fixed
(在检查模式下看不到 fixed
内联样式)
.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.
- 位置sticky在这里很有用。您可以将它用于 header 以及进度条。它会毫不费力地将元素固定在顶部。
- 要获得准确的位置,您需要使用
scrollTrigger
的 start
和 end
属性。这将告诉 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>
我正在尝试创建一个进度条,显示用户还有多少特定元素需要查看。以下是一些详细信息:
.postProgressBar
默认出现在.postHeroImage
下
- 当用户滚动时,我希望
.postProgressBar
根据.spacer
元素剩余的滚动量慢慢填充。 - 当
.postProgressBar
到达我的header
的底部时,我希望它变成fixed
到达header
的底部(并在.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>
当前问题:
.postProgressBar
不会变成fixed
(在检查模式下看不到fixed
内联样式).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.
- 位置sticky在这里很有用。您可以将它用于 header 以及进度条。它会毫不费力地将元素固定在顶部。
- 要获得准确的位置,您需要使用
scrollTrigger
的start
和end
属性。这将告诉 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>