如何使用animation-timeline属性添加延迟或平滑滚动驱动的动画?

问题描述 投票:0回答:1

我目前正在使用 CSS 滚动驱动动画 和新的

animation-timeline
属性。我所指的技术示例可以在这里看到:图像显示示例

但是,我面临一个问题:我想添加动画延迟以使动画平滑,尤其是在用鼠标滚动时。目前,动画看起来有点断断续续,因为 PC 上的鼠标滚动可能不太流畅,并且会以较大的即时步骤发生。

我尝试过使用传统的CSS属性animation-delay,但与滚动驱动的动画和

animation-timeline
属性一起使用时似乎没有任何效果。

以下是我想要的动画感觉的示例:

// Initialize Lenis
const lenis = new Lenis();

// Listen for the scroll event and log the event data
lenis.on('scroll', (e) => {
  console.log(e);
});

// Use requestAnimationFrame to continuously update the scroll
function raf(time) {
  lenis.raf(time);
  requestAnimationFrame(raf);
}

requestAnimationFrame(raf);
.animation-element-wrapper {
  display: grid;
  justify-content: center;
  background-color: green;
}

.animation-element {
  background-color: red;
  height: 50px;
  width: 50px;
  animation: move;
  animation-timeline: view(block);
}

@keyframes move {
  from {
    transform: translateY(0) rotate(0deg);
  }
  to {
    transform: translateY(-150px) rotate(360deg);
  }
}

// Smooth scroll styling

html.lenis, html.lenis body {
  height: auto;
}

.lenis.lenis-smooth {
  scroll-behavior: auto !important;
}

.lenis.lenis-smooth [data-lenis-prevent] {
  overscroll-behavior: contain;
}

.lenis.lenis-stopped {
  overflow: hidden;
}

.lenis.lenis-smooth iframe {
  pointer-events: none;
}
<script src="https://unpkg.com/[email protected]/dist/lenis.min.js"></script>
<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>
</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>
(stackoverflow 代码片段似乎不太适合平滑滚动,因此这里有一个代码笔,其中平滑滚动确实有效:平滑滚动示例

在本例中,我使用 JavaScript 库来实现整个页面的平滑滚动。我的目标是为基于 CSS 滚动的动画应用类似的平滑、缓慢移动的效果而不使用 JS 库

为了突出这个问题,这是另一个没有平滑滚动效果的示例:

.animation-element-wrapper {
  display: grid;
  justify-content: center;
  background-color: green;
}

.animation-element {
  background-color: red;
  height: 50px;
  width: 50px;
  animation: move;
  animation-timeline: view(block);
}

@keyframes move {
  from {
    transform: translateY(0) rotate(0deg);
  }
  to {
    transform: translateY(-150px) rotate(360deg);
  }
}
<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>
</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>
或者 Codepen:非平滑示例

流动性的差异是显而易见的,我想使用纯CSS复制更流畅的体验。

有没有办法仅使用 CSS 来引入延迟或平滑此动画行为,还是仍然需要 JavaScript?我主要寻找基于 CSS 的解决方案。

css scroll css-animations smooth-scrolling
1个回答
0
投票

我已经能够仅使用 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>

这一切都归功于这篇文章:https://www.bram.us/2023/10/23/css-scroll-detection/#lerp-effects

解释.
这里,滚动位置是从红方块的父级获取(并设置动画)的:

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

这里滚动位置被延迟(负责平滑度)。

.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)));
}
© www.soinside.com 2019 - 2024. All rights reserved.