滚动到视图时开始动画
Start animation when scrolled into view
我的网站上有进度条来直观地显示百分比,它有一个动画让它们随着页面滚动。但是,此动画会在页面加载后立即启动。
我的问题是进度条在页面下方,加载页面时无法及时看到动画。有什么方法可以让元素在视图中时才开始播放动画吗?
@keyframes example {
0% {
width: 0%;
}
10% {
width: 0%;
}
100% {
max-width: 100%;
}
}
.bara1 {
border-radius: 1px 25px 25px 1px;
padding: 16px;
background-color: #7ac1cf;
position: relative;
margin-bottom: -32px;
z-index: 2;
animation-name: example;
animation-duration: 6s;
}
.barb1 {
border-radius: 1px 25px 25px 1px;
padding: 16px;
background-color: #e3e3e3;
position: relative;
margin-bottom: 8px;
z-index: 1;
}
.textbox {
position: absolute;
color: #ffffff;
margin-top: -12px;
}
<div class="bara1" style="width: 92%">
<div class="textbox"><b>text</b>
<font size="2px" color="#def7fc">92%</font>
</div>
</div>
<div class="barb1"></div>
<div class="bara1" style="width: 78%">
<div class="textbox"><b>text</b>
<font size="2px" color="#def7fc">78%</font>
</div>
</div>
<div class="barb1"></div>
<div class="bara1" style="width: 56%">
<div class="textbox"><b>text</b>
<font size="2px" color="#def7fc">56%</font>
</div>
</div>
<div class="barb1"></div>
<div class="bara1" style="width: 40%">
<div class="textbox"><b>text</b>
<font size="2px" color="#def7fc">40%</font>
</div>
</div>
<div class="barb1"></div>
<div class="bara1" style="width: 31%">
<div class="textbox"><b>text</b>
<font size="2px" color="#def7fc">31%</font>
</div>
</div>
<div class="barb1"></div>
您需要使用 Intersection Observer API。基本上只有当栏开始可见时才会添加 class(在下面的示例中,我将其命名为 class animate
)。
我在你的 HTML 代码中添加了一个占位符来模拟栏前的内容,并将 animation-name: example
从 .bara1
移动到 .bara1.animate
const observer = new IntersectionObserver(intersections => {
intersections.forEach(({
target,
isIntersecting
}) => {
target.classList.toggle('animate', isIntersecting);
});
}, {
threshold: 0
});
document.querySelectorAll('.bara1').forEach(div => {
observer.observe(div);
});
#placeholder {
height: 100vh;
display: grid;
place-items: center;
font-size: 2rem;
border: 1px solid;
}
@keyframes example {
0% {
width: 0%;
}
10% {
width: 0%;
}
100% {
max-width: 100%;
}
}
.bara1 {
border-radius: 1px 25px 25px 1px;
padding: 16px;
background-color: #7ac1cf;
position: relative;
margin-bottom: -32px;
z-index: 2;
animation-duration: 6s;
}
.bara1.animate {
animation-name: example;
}
.barb1 {
border-radius: 1px 25px 25px 1px;
padding: 16px;
background-color: #e3e3e3;
position: relative;
margin-bottom: 8px;
z-index: 1;
}
.textbox {
position: absolute;
color: #ffffff;
margin-top: -12px;
}
<section id="placeholder">This is a placeholder</section>
<div class="bara1" style="width: 92%">
<div class="textbox"><b>text</b>
<font size="2px" color="#def7fc">92%</font>
</div>
</div>
<div class="barb1"></div>
<div class="bara1" style="width: 78%">
<div class="textbox"><b>text</b>
<font size="2px" color="#def7fc">78%</font>
</div>
</div>
<div class="barb1"></div>
<div class="bara1" style="width: 56%">
<div class="textbox"><b>text</b>
<font size="2px" color="#def7fc">56%</font>
</div>
</div>
<div class="barb1"></div>
<div class="bara1" style="width: 40%">
<div class="textbox"><b>text</b>
<font size="2px" color="#def7fc">40%</font>
</div>
</div>
<div class="barb1"></div>
<div class="bara1" style="width: 31%">
<div class="textbox"><b>text</b>
<font size="2px" color="#def7fc">31%</font>
</div>
</div>
<div class="barb1"></div>
您可以通过在滚动到视图中时向周围容器添加一个 class 来解决此问题,并仅为该 class(分别是其子项)定义动画。您可以在 scroll
事件的事件处理程序中调用该检查。
window.addEventListener('scroll', function() {
if (isScrolledIntoView(container)) {
container.classList.add('inView');
}
});
.inView .bara1 {
animation-name: example;
animation-duration: 6s;
}
为此,有必要定义一个函数来检查元素是否可见:
function isScrolledIntoView(elem) {
var rect = elem.getBoundingClientRect();
var elemTop = rect.top;
var elemBottom = rect.bottom;
var isVisible = (elemTop >= 0) && (elemBottom <= window.innerHeight);
return isVisible;
}
此外,重要的是省略所有 .bara1
的内联样式 (width
),而是使用 JavaScript 设置它们,例如使用 [=20] 中的文本=] 元素。否则会出现闪烁,这是由动画重置的完整(内联)宽度引起的。
const bars = document.querySelectorAll('.bara1');
for (let i = 0; i < bars.length; i++) {
const percent = bars[i].querySelector('font').textContent;
bars[i].style.width = percent;
}
工作示例:
let container = document.querySelector('#container');
function isScrolledIntoView(elem) {
var rect = elem.getBoundingClientRect();
var elemTop = rect.top;
var elemBottom = rect.bottom;
var isVisible = (elemTop >= 0) && (elemBottom <= window.innerHeight);
return isVisible;
}
window.addEventListener("scroll", function() {
if (isScrolledIntoView(container)) {
container.classList.add('inView');
const bars = document.querySelectorAll('.bara1');
for (let i = 0; i < bars.length; i++) {
const percent = bars[i].querySelector('font').textContent;
bars[i].style.width = percent;
}
}
});
#placeholder {
height: 500px;
border: 1px solid black;
}
@keyframes example {
0% {
width: 0%;
}
10% {
width: 0%;
}
100% {
max-width: 100%;
}
}
.bara1 {
width: 0;
border-radius: 1px 25px 25px 1px;
padding: 16px;
background-color: #7ac1cf;
position: relative;
margin-bottom: -32px;
z-index: 2;
}
.inView .bara1 {
animation-name: example;
animation-duration: 6s;
}
.barb1 {
border-radius: 1px 25px 25px 1px;
padding: 16px;
background-color: #e3e3e3;
position: relative;
margin-bottom: 8px;
z-index: 1;
}
.textbox {
position: absolute;
color: #ffffff;
margin-top: -12px;
}
<div id="placeholder">placeholder</div>
<div id="container">
<div class="bara1">
<div class="textbox"><b>text</b>
<font size="2px" color="#def7fc">92%</font>
</div>
</div>
<div class="barb1"></div>
<div class="bara1">
<div class="textbox"><b>text</b>
<font size="2px" color="#def7fc">78%</font>
</div>
</div>
<div class="barb1"></div>
<div class="bara1">
<div class="textbox"><b>text</b>
<font size="2px" color="#def7fc">56%</font>
</div>
</div>
<div class="barb1"></div>
<div class="bara1">
<div class="textbox"><b>text</b>
<font size="2px" color="#def7fc">40%</font>
</div>
</div>
<div class="barb1"></div>
<div class="bara1">
<div class="textbox"><b>text</b>
<font size="2px" color="#def7fc">31%</font>
</div>
</div>
<div class="barb1"></div>
</div>
我的网站上有进度条来直观地显示百分比,它有一个动画让它们随着页面滚动。但是,此动画会在页面加载后立即启动。
我的问题是进度条在页面下方,加载页面时无法及时看到动画。有什么方法可以让元素在视图中时才开始播放动画吗?
@keyframes example {
0% {
width: 0%;
}
10% {
width: 0%;
}
100% {
max-width: 100%;
}
}
.bara1 {
border-radius: 1px 25px 25px 1px;
padding: 16px;
background-color: #7ac1cf;
position: relative;
margin-bottom: -32px;
z-index: 2;
animation-name: example;
animation-duration: 6s;
}
.barb1 {
border-radius: 1px 25px 25px 1px;
padding: 16px;
background-color: #e3e3e3;
position: relative;
margin-bottom: 8px;
z-index: 1;
}
.textbox {
position: absolute;
color: #ffffff;
margin-top: -12px;
}
<div class="bara1" style="width: 92%">
<div class="textbox"><b>text</b>
<font size="2px" color="#def7fc">92%</font>
</div>
</div>
<div class="barb1"></div>
<div class="bara1" style="width: 78%">
<div class="textbox"><b>text</b>
<font size="2px" color="#def7fc">78%</font>
</div>
</div>
<div class="barb1"></div>
<div class="bara1" style="width: 56%">
<div class="textbox"><b>text</b>
<font size="2px" color="#def7fc">56%</font>
</div>
</div>
<div class="barb1"></div>
<div class="bara1" style="width: 40%">
<div class="textbox"><b>text</b>
<font size="2px" color="#def7fc">40%</font>
</div>
</div>
<div class="barb1"></div>
<div class="bara1" style="width: 31%">
<div class="textbox"><b>text</b>
<font size="2px" color="#def7fc">31%</font>
</div>
</div>
<div class="barb1"></div>
您需要使用 Intersection Observer API。基本上只有当栏开始可见时才会添加 class(在下面的示例中,我将其命名为 class animate
)。
我在你的 HTML 代码中添加了一个占位符来模拟栏前的内容,并将 animation-name: example
从 .bara1
移动到 .bara1.animate
const observer = new IntersectionObserver(intersections => {
intersections.forEach(({
target,
isIntersecting
}) => {
target.classList.toggle('animate', isIntersecting);
});
}, {
threshold: 0
});
document.querySelectorAll('.bara1').forEach(div => {
observer.observe(div);
});
#placeholder {
height: 100vh;
display: grid;
place-items: center;
font-size: 2rem;
border: 1px solid;
}
@keyframes example {
0% {
width: 0%;
}
10% {
width: 0%;
}
100% {
max-width: 100%;
}
}
.bara1 {
border-radius: 1px 25px 25px 1px;
padding: 16px;
background-color: #7ac1cf;
position: relative;
margin-bottom: -32px;
z-index: 2;
animation-duration: 6s;
}
.bara1.animate {
animation-name: example;
}
.barb1 {
border-radius: 1px 25px 25px 1px;
padding: 16px;
background-color: #e3e3e3;
position: relative;
margin-bottom: 8px;
z-index: 1;
}
.textbox {
position: absolute;
color: #ffffff;
margin-top: -12px;
}
<section id="placeholder">This is a placeholder</section>
<div class="bara1" style="width: 92%">
<div class="textbox"><b>text</b>
<font size="2px" color="#def7fc">92%</font>
</div>
</div>
<div class="barb1"></div>
<div class="bara1" style="width: 78%">
<div class="textbox"><b>text</b>
<font size="2px" color="#def7fc">78%</font>
</div>
</div>
<div class="barb1"></div>
<div class="bara1" style="width: 56%">
<div class="textbox"><b>text</b>
<font size="2px" color="#def7fc">56%</font>
</div>
</div>
<div class="barb1"></div>
<div class="bara1" style="width: 40%">
<div class="textbox"><b>text</b>
<font size="2px" color="#def7fc">40%</font>
</div>
</div>
<div class="barb1"></div>
<div class="bara1" style="width: 31%">
<div class="textbox"><b>text</b>
<font size="2px" color="#def7fc">31%</font>
</div>
</div>
<div class="barb1"></div>
您可以通过在滚动到视图中时向周围容器添加一个 class 来解决此问题,并仅为该 class(分别是其子项)定义动画。您可以在 scroll
事件的事件处理程序中调用该检查。
window.addEventListener('scroll', function() {
if (isScrolledIntoView(container)) {
container.classList.add('inView');
}
});
.inView .bara1 {
animation-name: example;
animation-duration: 6s;
}
为此,有必要定义一个函数来检查元素是否可见:
function isScrolledIntoView(elem) {
var rect = elem.getBoundingClientRect();
var elemTop = rect.top;
var elemBottom = rect.bottom;
var isVisible = (elemTop >= 0) && (elemBottom <= window.innerHeight);
return isVisible;
}
此外,重要的是省略所有 .bara1
的内联样式 (width
),而是使用 JavaScript 设置它们,例如使用 [=20] 中的文本=] 元素。否则会出现闪烁,这是由动画重置的完整(内联)宽度引起的。
const bars = document.querySelectorAll('.bara1');
for (let i = 0; i < bars.length; i++) {
const percent = bars[i].querySelector('font').textContent;
bars[i].style.width = percent;
}
工作示例:
let container = document.querySelector('#container');
function isScrolledIntoView(elem) {
var rect = elem.getBoundingClientRect();
var elemTop = rect.top;
var elemBottom = rect.bottom;
var isVisible = (elemTop >= 0) && (elemBottom <= window.innerHeight);
return isVisible;
}
window.addEventListener("scroll", function() {
if (isScrolledIntoView(container)) {
container.classList.add('inView');
const bars = document.querySelectorAll('.bara1');
for (let i = 0; i < bars.length; i++) {
const percent = bars[i].querySelector('font').textContent;
bars[i].style.width = percent;
}
}
});
#placeholder {
height: 500px;
border: 1px solid black;
}
@keyframes example {
0% {
width: 0%;
}
10% {
width: 0%;
}
100% {
max-width: 100%;
}
}
.bara1 {
width: 0;
border-radius: 1px 25px 25px 1px;
padding: 16px;
background-color: #7ac1cf;
position: relative;
margin-bottom: -32px;
z-index: 2;
}
.inView .bara1 {
animation-name: example;
animation-duration: 6s;
}
.barb1 {
border-radius: 1px 25px 25px 1px;
padding: 16px;
background-color: #e3e3e3;
position: relative;
margin-bottom: 8px;
z-index: 1;
}
.textbox {
position: absolute;
color: #ffffff;
margin-top: -12px;
}
<div id="placeholder">placeholder</div>
<div id="container">
<div class="bara1">
<div class="textbox"><b>text</b>
<font size="2px" color="#def7fc">92%</font>
</div>
</div>
<div class="barb1"></div>
<div class="bara1">
<div class="textbox"><b>text</b>
<font size="2px" color="#def7fc">78%</font>
</div>
</div>
<div class="barb1"></div>
<div class="bara1">
<div class="textbox"><b>text</b>
<font size="2px" color="#def7fc">56%</font>
</div>
</div>
<div class="barb1"></div>
<div class="bara1">
<div class="textbox"><b>text</b>
<font size="2px" color="#def7fc">40%</font>
</div>
</div>
<div class="barb1"></div>
<div class="bara1">
<div class="textbox"><b>text</b>
<font size="2px" color="#def7fc">31%</font>
</div>
</div>
<div class="barb1"></div>
</div>