Сделайте элемент липким до тех пор, пока анимация, управляемая прокруткой, не завершится

Вот чего я пытаюсь достичь:

-когда элементы становятся видимыми пользователю, для них один за другим запускается анимация вращения при прокрутке, и все 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>

🤔 А знаете ли вы, что...
С помощью JavaScript можно создавать клиентские приложения для мобильных устройств с использованием фреймворков, таких как React Native и NativeScript.


1
69
1

Ответ:

Решено

Хотите попробовать это?

Я использовал 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>

Интересные вопросы для изучения