79159046

Date: 2024-11-05 12:16:54
Score: 1
Natty:
Report link

I've been able to figure it out by using only CSS:

@property --scroll-position {
  syntax: '<number>';
  inherits: true;
  initial-value: 0;
}

@property --scroll-position-delayed {
  syntax: '<number>';
  inherits: true;
  initial-value: 0;
}

@keyframes adjust-pos {
  to {
    --scroll-position: 1;
    --scroll-position-delayed: 1;
  }
}

.animation-element-wrapper {
  animation: adjust-pos linear both;
  animation-timeline: view(block);
  
  display: grid;
  justify-content: center;
  background-color: green;
}

.animation-element {
  transition: --scroll-position-delayed 0.15s linear;
}

.red-square {
  background-color: red;
  height: 50px;
  width: 50px;
  transform: translateY(calc(-150px * var(--scroll-position-delayed)));
}

/* Display debugging information */
#debug {
  position: fixed;
  top: 50%;
  left: 75%;
  translate: -50% -50%;
  background: white;
  border: 1px solid #ccc;
  padding: 1rem;
  
  & li {
    list-style: none;
  }
  
  counter-reset: scroll-position calc(var(--scroll-position) * 100) scroll-position-delayed calc(var(--scroll-position-delayed) * 100);
  
  [data-id="--scroll-position"]::after {
    content: "--scroll-position: " counter(scroll-position);
  }
  [data-id="--scroll-position-delayed"]::after {
    content: "--scroll-position-delayed: " counter(scroll-position-delayed);
  }
}
<h1>Hello World!</h1>
<h1>Hello World!</h1>
<h1>Hello World!</h1>
<h1>Hello World!</h1>
<h1>Hello World!</h1>
<h1>Hello World!</h1>
<h1>Hello World!</h1>
<h1>Hello World!</h1>
<h1>Hello World!</h1>

<div class="animation-element-wrapper">
  <div class="animation-element">
    <div class="red-square"></div>
    <div id="debug">
      <ul>
        <li data-id="--scroll-position"></li>
        <li data-id="--scroll-position-delayed"></li>
      </ul>
    </div>
  </div>
</div>

<h1>Hello World!</h1>
<h1>Hello World!</h1>
<h1>Hello World!</h1>
<h1>Hello World!</h1>
<h1>Hello World!</h1>
<h1>Hello World!</h1>
<h1>Hello World!</h1>
<h1>Hello World!</h1>
<h1>Hello World!</h1>

This is all thanks to this article: https://www.bram.us/2023/10/23/css-scroll-detection/#lerp-effects

Explanation.
Here the scroll position is fetched (and animated) from the parent of the red-square:

    @keyframes adjust-pos {
      to {
        --scroll-position: 1;
        --scroll-position-delayed: 1;
      }
    }    
    
    .animation-element-wrapper {
        animation: adjust-pos linear both;
        animation-timeline: view(block);

Here the scroll-position is delayed (responsible for the smoothness).

.animation-element {
  transition: --scroll-position-delayed 0.15s linear;
}

Here the delayed scroll-position is used to animate the "red-square":

.red-square {
  background-color: red;
  height: 50px;
  width: 50px;
  transform: translateY(calc(-150px * var(--scroll-position-delayed)));
}
Reasons:
  • Blacklisted phrase (0.5): thanks
  • Blacklisted phrase (1): this article
  • Long answer (-1):
  • Has code block (-0.5):
  • Self-answer (0.5):
  • Low reputation (0.5):
Posted by: Jesper Ingels