【问题标题】:@keyframe animation on scroll event@keyframe 滚动事件上的动画
【发布时间】:2020-04-14 11:20:46
【问题描述】:

我正在使用可变字体,并希望在滚动时使用@keyframes 对其进行动画处理,然后在用户停止滚动时不进行动画处理。

我可以制作动画,但是当你停止滚动时,动画会停止并迅速回到起始位置,这使它看起来非常跳跃。

为了让它更加平滑,我想知道是否有一种方法可以在用户停止滚动时获取动画的当前位置,然后完成该动画循环然后停止,而不是是否立即回到起始位置?

由于我无法使用 @font-face 将变量字体加载到 jsfiddle 中,所以我将它放在这里: http://slug.directory/GX/

这里是 js...


    $(document).ready(function() {

    var scrollTimerId;

    $(window).scroll(function() {
        if (!scrollTimerId)
            $('body').addClass('scrolling');

        clearTimeout(scrollTimerId);
        scrollTimerId = setTimeout(function(){
            $('body').removeClass('scrolling');
            scrollTimerId = undefined;
        },150);
    });
});

和 css...

@keyframes changewidth {
  0% {
    font-variation-settings: 'wght' 1;
  }

  100% {
    font-variation-settings: 'wght' 100;
  }
}

.scrolling {
  animation-duration: 0.5s;
  animation-name: changewidth;
  animation-iteration-count: infinite;
  animation-direction: alternate;
 animation-fill-mode: forwards;
}

body {
    font-family: "AG GX", Helvetica, sans-serif;
    font-weight: normal;
    font-style: normal;
    font-size: 2vw;
    line-height: 2vw;
    font-variation-settings: 'wght' 1;
    height: 300vh;
}

div {
  position: fixed;
}

提前致谢!

【问题讨论】:

  • 我正在使用可变字体,并希望在滚动时使用@keyframes 对其进行动画处理,然后在用户停止滚动时不进行动画处理。 如何制作动画? 我可以制作动画。我打开了链接,滚动时它没有动画。

标签: javascript jquery css-animations keyframe onscroll


【解决方案1】:

您面临的情况只是如何从动画中的任意点过渡到静态位置。
不幸的是,没有 CSS 定义的方式,所以我们不得不求助于 javascript 来处理它。

基本思想是手动触发该转换。 getComputedStyle 可以为您提供动画当前的值,因此我们可以将其设置在元素的内联样式中,然后在强制回流后立即将其删除以触发到原始位置的过渡。

不幸的是 Safari 的行为很奇怪,我们也必须切换转换属性,使这个操作强制 3 次同步重排......

这是一个使用移动框的示例,因为它更容易设置为 sn-p:

const box = document.getElementById( 'box' );
onclick = e => {
  box.style.setProperty( 'transform', getComputedStyle( box ).transform );
  // set the inline style to the current value
  box.classList.toggle( 'anim' ); // disable the animation
  
  box.offsetWidth; // trigger a first reflow just for Safari
  box.classList.toggle( 'transition' ); // toggle the transition
  box.offsetWidth; // trigger an other reflow so the browser knows where we are
  box.style.removeProperty( 'transform' ); // come back to initial position
};
#box {
  width: 50px; 
  height: 50px;
  background: lime;
}
.anim {
  animation: move 2.5s infinite;
}
.transition {
  transition: transform 2s;
}
@keyframes move {
  from { transform: translate(0, 0) rotate(0deg); } /* Safari needs a 'from' */
  to { transform: translate(100vw, 0) rotate(360deg); }
}
<pre>click to toggle the animation on/off</pre>
<div id="box" class="transition"></div>

使用您的代码:

$(window).scroll(function() {
  if (!scrollTimerId)
    $('body').addClass('scrolling')
      .removeClass('transition-font-variation');

  clearTimeout(scrollTimerId);
  scrollTimerId = setTimeout(function() {
    const val = getComputedStyle(document.body).getPropertyValue('font-variation-settings');
    document.body.style.setProperty( 'font-variation-settings', val );
    $('body').removeClass('scrolling');
    document.body.offsetWidth; // force reflow
    $('body').addClass('transition-font-variation');
    document.body.offsetWidth; // force reflow
    document.body.style.removeProperty( 'font-variation-settings' );
    scrollTimerId = undefined;
  }, 150);
});
body {
    font-family: "AG GX", Helvetica, sans-serif;
    font-weight: normal;
    font-style: normal;
    font-size: 2vw;
    line-height: 2vw;
    font-variation-settings: 'wght' 1;
    height: 300vh;
}
body.transition-font-variation {
  transition: font-variation-settings 2s;
}

(如果您想从 OP 的网站尝试,请在应用这些更改之前在您的 js 控制台中输入 $(window).off('scroll'))。

【讨论】:

  • 谢谢@Kaiido 你的回答正是我所希望的。它在 Chrome 中工作,但在 Safari 中,它仍然会快速回到开头,而不是顺利完成旋转。这里有什么想法吗?如果这也适用于 Safari,那么我很乐意将您的答案标记为正确。我已将您的代码放在这里进行实时检查:slug.directory/GX1
  • @R-J 你是对的,我没有在 Safari 中测试过,它们对过渡和动画的表现非常奇怪(离完全被破坏不远)。无论如何,我为 Safari 添加了一个修复程序。
  • 宾果游戏!搞定了!现在也在 Safari 中运行良好。谢谢你!赏金是你的 :-) + 如果你想从 OP 的网站上尝试这些更改,你能否在应用这些更改之前在你的 js 控制台中解释你的意思)。
  • 它适用于希望通过浏览器的开发工具将其应用到您的网站的读者。在应用这个新的处理程序之前,他们必须删除您自己的处理程序。
【解决方案2】:

应该这样做。

CSS:

@font-face {
    font-family: "AG GX";
    src: url('../fonts/AccidenzTestGX.ttf') format('truetype');
    font-weight: normal;
    font-style: normal;
}

@keyframes changewidth {
  from, to {
    font-variation-settings: 'wght' 1;
  }

  50% {
    font-variation-settings: 'wght' 100;
  }
}

.scrolling {
  animation-duration: 0.5s;
  animation-name: changewidth;
  animation-iteration-count: infinite;
}

body {
    font-family: "AG GX", Helvetica, sans-serif;
    font-weight: normal;
    font-style: normal;
    font-size: 2vw;
    line-height: 2vw;
    height: 300vh;
    font-variation-settings: 'wght' 1;
    transition: font-variation-settings 0.5s;
}

div {
  position: fixed;
  }
}

我稍微更改了动画并删除了animation-direction: alternate; 以及animation-fill-mode: forwards;。让你知道。

JS:

$(document).ready(function() {
  $(window).scroll(function() {
    $('body').addClass('scrolling');
    clearTimeout($.data(this, 'scrollTimer'));
    $.data(this, 'scrollTimer', setTimeout(function() {
      var computedStyle = $('body').css('font-variation-settings');
      $('body').removeClass('scrolling');
      $('body').css('font-variation-settings', computedStyle);
      setTimeout(function() {
        $('body').css('font-variation-settings', "'wght' 1");
      }, 500);
    }));
  });
});

JS 解释:

第一步:在滚动时添加scrolling类。

第 2 步: 添加一个setTimeout,这样我们就可以在用户停止滚动时激活一个事件。 (我看到你已经有了类似的东西,太好了)。

第 3 步:当用户停止滚动时,获取当前的 font-variation-settings 并将它们存储为变量 (computedStyle)。

第4步:删除scrolling类并将font-variation-settings设置为computedStyle

第 5 步:等待 500 毫秒,以便开始转换。在.5s之后,我们重置font- variation-settings


JSFiddletransform: rotate() 的示例。

来源:这篇CSS-Tricks 文章和这个Stack Overflow 问题。

【讨论】:

  • 大家好,非常感谢您的贡献——超出我的预期。我正在彻底研究每一个,以测试哪个最适合该站点。很快,谢谢!
  • 感谢您的回答,但它仍然会弹回原位。有什么想法吗?如果您想检查我的意思,我已将您的版本放在这里:slug.directory/GX2
【解决方案3】:

我无法访问您的字体,所以我使用了 css 属性 color

为了跟踪动画结束点,我在 body 上使用了 animationiteration 事件。逻辑是,

如果动画完成“奇数个循环”,则更改 coloranimation-direction,如果没有,则什么也不做

这是我添加的,

$('body').on('animationiteration', function() {
  if(started) {
    $('body').removeClass('scrolling');
    scrollTimerId = undefined;

    var cycles = Math.round((Date.now() - now) / 1000);
    if(cycles % 2) {
      if(currColor == 'rgb(0, 128, 0)') {
        currColor = 'rgb(255, 0, 0)';
        animDir = 'alternate-reverse';
      } else {
        currColor = 'rgb(0, 128, 0)';
        animDir = 'alternate';
      }
    }

    started = false;
    $('body').css('color', currColor);
    console.log(currColor, animDir, cycles);
  }
});

此外,我使用started 来检查动画是否已开始,并相应地设置属性animation-direction 仅一次

$(document).ready(function() {

  var scrollTimerId;
  var currColor = 'rgb(0, 128, 0)';
  var animDir = 'alternate';
  var started = false;
  var now;

  $('body').css('color', currColor);
  $(window).scroll(function() {
    if(!started) {
      if (!scrollTimerId)
        $('body').addClass('scrolling');

      $('.scrolling').css('animation-direction', animDir);
      started = true;
      now = Date.now();
    }
    
    clearTimeout(scrollTimerId);
    scrollTimerId = setTimeout(function() {
      $('body').on('animationiteration', function() {
        if(started) {
          $('body').removeClass('scrolling');
          scrollTimerId = undefined;
          
          var cycles = Math.round((Date.now() - now) / 1000);
          if(cycles % 2) {
            if(currColor == 'rgb(0, 128, 0)') {
              currColor = 'rgb(255, 0, 0)';
              animDir = 'alternate-reverse';
            } else {
              currColor = 'rgb(0, 128, 0)';
              animDir = 'alternate';
            }
          }

          started = false;
          $('body').css('color', currColor);
        }
      });
    }, 500);
  });

});
@keyframes color {
  0% {
    color: green;
  }
  100% {
    color: red;
  }
}

.scrolling {
  animation-duration: 1s;
  animation-name: color;
  animation-iteration-count: infinite;
  animation-direction: alternate;
  animation-fill-mode: forwards;
}

body {
  font-weight: normal;
  font-style: normal;
  font-size: 2vw;
  line-height: 2vw;
  height: 300vh;
}

div {
  position: fixed;
}
<script src="https://code.jquery.com/jquery-3.4.1.min.js" integrity="sha256-CSXorXvZcTkaix6Yvo6HppcZGetbYMGWSFlBw8HfCJo=" crossorigin="anonymous"></script>
<div>
  <p>To in ni test ommos ratiam, nihitat istinctatum voluptatio bea ipsantur sum quod magnatusant modi conse doloria di quosam necatatiost pro voluptam quae doluptasi. To in ni test ommos ratiam, nihitat istinctatum voluptatio bea ipsantur sum quod magnatusant
    modi conse doloria di quosam necatatiost pro voluptam quae doluptasi.</p>

  <p>To in ni test ommos ratiam, nihitat istinctatum voluptatio bea ipsantur sum quod magnatusant modi conse doloria di quosam necatatiost pro voluptam quae doluptasi sinctot amenimodia quam, cones is et aut la voloria non rehentus eium, volorit parum re,
    volorei cipidust, ut es doluptaquae coratum quide moluptaquis aut latiorrum adipitat lab ipsapicienim qui nusciun tioribus ea voluptam sim dolo experfe reratusae velitature pa pos ut et que simporrum ut ilitam, incto iunt et hitam natis net vellignimod
    magnis eum re odipiti ssequib earuptatia anto mi, qui derera dipsa volorendis volum es qui consequis acernam rem consequi aut eaquiatia destemo luptur, sae volo berumqui apicia sum que mo moluptium remoluptat qui sumque nonserro officiet ditiae int
    et elibus idellabore volor serum volent.</p>

  <p>To in ni test ommos ratiam, nihitat istinctatum voluptatio bea ipsantur sum quod magnatusant modi conse doloria di quosam necatatiost pro voluptam quae doluptasi sinctot amenimodia quam, cones is et aut la voloria non rehentus eium, volorit parum re,
    volorei cipidust, ut es doluptaquae coratum quide moluptaquis aut latiorrum adipitat lab ipsapicienim qui nusciun tioribus ea voluptam sim dolo experfe reratusae velitature pa pos ut et que simporrum ut ilitam, incto iunt et hitam natis net vellignimod
    magnis eum re odipiti ssequib earuptatia anto mi, qui derera dipsa volorendis volum es qui consequis acernam rem consequi aut eaquiatia destemo luptur, sae volo berumqui apicia sum que mo moluptium remoluptat qui sumque nonserro officiet ditiae int
    et elibus idellabore volor serum volent.</p>



</div>

Try it live!(查看控制台了解更多详情)


您可能想知道为什么我没有直接在body 上使用animationend。这是因为你的动画是无限循环的;)

【讨论】:

  • @R-J:我删除了lastScroll 以使其更简单。有什么反馈吗?
  • 我喜欢你在这里的想法,但我认为它在实践中行不通。我已将您的答案放在这里进行检查:slug.directory/GX3 我是否正确实施了它,因为它不再旋转了?谢谢
  • @R-J:我无法在网站上调试脚本(我尝试了控制台日志,但没有成功)。那么,您愿意分享您的字体以便我在本地进行调试吗?这会很有帮助。
  • 当然,如果您查看字体,您(c)知道(s)什么(s)。期待结果 :-) 谢谢!
  • @R-J:我没看懂你第一句话的结尾。我是说你给了你的字体url('../fonts/AccidenzTestGX.ttf') 的相对路径,因此我永远无法访问你的字体。你怎么说它已经存在了?
猜你喜欢
  • 2016-05-16
  • 2018-05-27
  • 1970-01-01
  • 1970-01-01
  • 2021-11-23
  • 2013-08-31
  • 1970-01-01
  • 1970-01-01
  • 2014-07-01
相关资源
最近更新 更多