Вот чего я пытаюсь достичь:
-когда элементы становятся видимыми пользователю, для них один за другим запускается анимация вращения при прокрутке, и все 3 элемента становятся липкими (это означает, что они не исчезают, пока пользователь прокручивает вниз), пока анимация на последний закончен. -когда анимация завершена, страница возвращается к своему обычному поведению
Этот код не делает элементы липкими, когда это необходимо.
document.addEventListener('DOMContentLoaded', function() {
const elements = document.querySelectorAll('.animation');
let delay = 0;
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
entry.target.style.animationDelay = `${delay}s`;
entry.target.style.animationPlayState = 'running';
console.info('running');
// Add sticky class when the element is in view
entry.target.classList.add('sticky');
delay += 2.5; // Increase delay for the next element
observer.unobserve(entry.target); // Stop observing once the animation is triggered
}
});
}, {
threshold: 0.5
}); // Trigger when 50% of the element is in view
elements.forEach(element => {
console.info('paused');
element.style.animationPlayState = 'paused'; // Pause animation until triggered
observer.observe(element);
// Remove sticky class after the animation ends
element.addEventListener('animationend', () => {
console.info('animationend')
element.classList.remove('sticky');
});
});
});.content {
width: 75%;
max-width: 800px;
margin: 0 auto;
}
p,
h1 {
font-family: Arial, Helvetica, sans-serif;
}
h1 {
font-size: 3rem;
}
p {
font-size: 1.5rem;
line-height: 1.5;
}
.animation {
view-timeline: --subjectReveal block;
animation-timeline: --subjectReveal;
width: 200px;
height: 200px;
background-color: bisque;
animation-iteration-count: 1;
animation-name: mymove;
animation-duration: 3s;
position: relative;
/* Normal position */
}
.animation:nth-child(1) {
animation-delay: calc(var(--subjectReveal) * 1);
}
.animation:nth-child(2) {
animation-delay: calc(var(--subjectReveal) * 2);
}
.animation:nth-child(3) {
animation-delay: calc(var(--subjectReveal) * 3);
}
/* Define the sticky behavior */
.sticky {
position: sticky;
top: 10px;
/* Adjust top as needed */
z-index: 10;
/* Ensure it stays on top */
}
@keyframes mymove {
0% {
opacity: 1;
transform: rotate(0deg);
}
50% {
opacity: 1;
transform: rotate(90deg);
}
100% {
opacity: 1;
transform: rotate(180deg);
}
}
.as-console-wrapper { height:50px; }Scroll this
<div style = "height:1000px; min-height: 300px; max-width: 100%; display: flex; flex-direction: row; justify-content: space-between; align-items: center;">
<div class = "animation"></div>
<div class = "animation"></div>
<div class = "animation"></div>
</div>@NINE Я добавил только html-часть с элементами, к которым применяется анимация.
Я немного изменил ваш CSS (<div style = "height:1000px;), чтобы показать эффект, и ограничил высоту консоли фрагмента.
@mplungjan спасибо за разъяснение моего кода! есть идеи, как реализовать то, что показано на гифке?
Не могли бы вы прежде всего уточнить, как именно вы хотите, чтобы это вело себя? Ваше анимированное изображение предполагает, что анимация поворота начнется, когда элементы достигнут середины экрана, но в вашем коде написано // Trigger when 50% of the element is in view. А в вашем классе sticky есть top: 10px;, что означает, что элементы станут липкими только тогда, когда они находятся на расстоянии менее 10 пикселей от верха прокручиваемого контейнера - это также не соответствует тому, чего вы на самом деле хотите достичь.
// Remove sticky class after the animation ends — ваше изображение предполагает, что вы хотите, чтобы они все стали липкими, а затем снова отклеились одновременно. Но ваши анимации завершатся в разное время из-за разных начальных задержек — поэтому не следует удалять класс из каждого отдельного элемента, когда закончилась его собственная анимация; но удалите его из всех, когда анимация последнего элемента завершится.
Вы уже определили animation-delay в своем CSS — не знаете, зачем тогда вам нужно снова устанавливать его в части JS? Разве не имело бы гораздо больше смысла, если бы вы просто наблюдали пересечение одного из этих элементов (поскольку они все равно находятся в одной и той же позиции по оси Y), а затем запускали анимацию для всех из них (например, просто задав контейнеру элемент класса) - с задержками, уже установленными в CSS?



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


Хотите попробовать это?
Я использовал CSS animation-range-start, он был в предоставленном вами коде..
но кажется, что поддерживать ее в Firefox и Safari сложно, поскольку это экспериментальная функция.
Я поработал над движениями, которые вам нужны, поэтому используйте те части, на которые вы можете обратиться!
Надеюсь, это поможет :)
document.addEventListener('DOMContentLoaded', function() {
const elementsContent = document.querySelector('.animation-content');
const elements = document.querySelectorAll('.animation');
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
elements.forEach((element) => {
element.style.animationName = 'mymove'; // add animation to div
element.style.animationPlayState = 'running'; // Start animation
});
observer.unobserve(entry.target); // Stop observing
}
});
}, {
threshold: 0.8
}); // Trigger when 80% of the element is in view
observer.observe(elementsContent);
});html,
body {
margin: 0;
padding: 2vw;
background: #222;
}
.animation-wrap {
height: 300vh;
background: #fff;
}
.animation-content {
display: flex;
justify-content: space-around;
align-items: center;
height: 100vh;
position: sticky;
top: 0;
}
.animation {
view-timeline: --subjectReveal block;
animation-timeline: --subjectReveal;
animation-range-start: entry 200%;
height: 0; /* ignore this, just for square */
width: 20vw; /* ignore this, just for square */
padding-bottom:20vw; /* ignore this, just for square */
background-color: bisque;
animation-iteration-count: 1;
animation-duration: 3s;
animation-fill-mode: forwards;
/*whenendanimation,holdstartstate*/
animation-play-state: paused;
/*pausedatfirst*/
position: relative;
/*Normalposition*/
}
.animation:nth-child(1) {
animation-delay: 0s;
}
.animation:nth-child(2) {
animation-delay: 1.4s;
}
.animation:nth-child(3) {
animation-delay: 2.8s;
}
@keyframes mymove {
0% {
transform: rotate(0deg);
}
25% {
transform: rotate(360deg);
}
100% {
transform: rotate(360deg);
}
}
div[class* = "other-content"] {
display: flex;
align-items: center;
justify-content: center;
text-align: center;
font-size: 3rem;
}
.other-content_01 {
height: 400px;
background: #eee;
}
.other-content_02 {
height: 1000px;
background: #ddd;
}<!DOCTYPE html>
<html lang = "en">
<head>
<meta charset = "UTF-8">
<meta name = "viewport" content = "width=device-width, initial-scale=1.0">
<title>Document</title>
<link rel = "stylesheet" href = "test.css">
</head>
<body>
<div class = "other-content_01">
Scroll Page :)
</div>
<div class = "animation-wrap">
<div class = "animation-content">
<div class = "animation"></div>
<div class = "animation"></div>
<div class = "animation"></div>
</div>
</div>
<div class = "other-content_02">
Thank you!
</div>
<script src = "test.js"></script>
</body>
</html>Спасибо большое, именно этого я и добивался :)
Эта анимация возникает только при прокрутке, но в текущем коде, похоже, нет места для прокрутки. Должен ли я произвольно увеличить высоту и воспроизвести ее?