@keyframe анимация при прокрутке события

Я использую переменный шрифт и хотел бы анимировать его с помощью @keyframes при прокрутке, а затем не анимировать, когда пользователь прекращает прокрутку.

Я могу заставить анимацию работать, однако, когда вы прекращаете прокрутку, анимация останавливается и возвращается в исходное положение, что делает ее очень дерганой.

Чтобы сделать его более плавным, мне интересно, есть ли способ, которым, когда пользователь перестает прокручивать, можно получить текущую позицию анимации, а затем завершить этот цикл анимации, а затем остановить, вместо немедленной привязки вернуться в исходное положение?

Поскольку я не могу загрузить переменный шрифт в jsfiddle с помощью @font-face, я разместил его здесь: http://slug.directory/GX/

Вот жс...


    $(document).ready(function() {

    var scrollTimerId;

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

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

и ссс...

@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;
}

Заранее спасибо!


person R-G    schedule 14.04.2020    source источник
comment
Я использую переменный шрифт и хочу анимировать его с помощью @keyframes при прокрутке, а затем не анимировать, когда пользователь останавливает прокрутку. Как анимировать? Я могу заставить анимацию работать. Я открыл ссылку, и она не анимируется при прокрутке.   -  person Richard    schedule 18.04.2020


Ответы (3)


Ситуация, с которой вы столкнулись, заключается в том, как просто перейти из любой точки анимации в статическую позицию.
К сожалению, не существует способа, определенного в CSS, поэтому нам приходится прибегать к javascript, чтобы справиться с этим.

Основная идея состоит в том, чтобы инициировать этот переход вручную. getComputedStyle может дать вам текущее значение вашей анимации, поэтому мы можем установить его во встроенном стиле нашего элемента, а затем удалить его сразу после срабатывания принудительного перекомпоновки для перехода в исходное положение.

К сожалению, Safari ведет себя странно, и нам также приходится переключать свойство перехода, в результате чего эта операция вызывает 3 синхронных перекомпоновки...

Вот пример использования движущегося блока, так как его проще настроить как фрагмент:

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;
}

(введите $(window).off('scroll') в консоли js перед применением этих изменений, если вы хотите попробовать это с веб-сайта OP).

person Kaiido    schedule 17.04.2020
comment
Спасибо, @Kaiido. Ты ответил именно на то, на что я надеялся. Он работает в Chrome, однако в Safari он по-прежнему возвращается к началу, а не плавно завершает вращение. Любые идеи здесь? Если это работает и в Safari, я буду рад отметить ваш ответ как правильный. Я разместил ваш код здесь, чтобы проверить вживую: slug.directory/GX1 - person R-G; 21.04.2020
comment
@ R-J, вы правы, я не тестировал в Safari, и они ведут себя очень странно в отношении переходов и анимации (недалеко от того, чтобы полностью сломаться с их стороны). Во всяком случае, я добавил исправление для Safari. - person Kaiido; 22.04.2020
comment
Бинго! Успешно справился! теперь хорошо работает и в Safari. спасибо! Bounty за вами :-) + не могли бы вы также объяснить, что вы подразумеваете под: '(наберите $(window).off('scroll')' в вашей консоли js перед применением этих изменений, если вы хотите попробовать это с веб-сайта OP). - person R-G; 22.04.2020
comment
Он предназначен для читателей, которые хотят применить его на вашем веб-сайте из инструментов разработки своего браузера. Они должны удалить ваш собственный обработчик, прежде чем применять этот новый. - person Kaiido; 22.04.2020

Это должно сделать это.

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:

Шаг 1. Добавьте класс scrolling при прокрутке.

Шаг 2. Добавьте setTimeout, чтобы мы могли активировать событие, когда пользователь прекращает прокрутку. (Я видел, что у вас уже было что-то подобное, это здорово).

Шаг 3. Когда пользователь перестанет прокручивать, получите текущие font-variation-settings и сохраните их как переменную (computedStyle).

Шаг 4. Удалите класс scrolling и задайте для font-variation-settings значение computedStyle.

Шаг 5. Подождите 500 мс, чтобы начать переход. После .5s сбрасываем font- variation-settings.


Пример на JSFiddle с transform: rotate().

Источник: этот CSS-Tricks статью и этот вопрос Stack Overflow.

person barhatsor    schedule 18.04.2020
comment
Привет всем! Большое спасибо за ваш вклад — больше, чем я ожидал. Я тщательно изучаю каждый, чтобы проверить, какой из них лучше всего подходит для сайта. Скоро, спасибо! - person R-G; 21.04.2020
comment
спасибо за ответ, однако он все равно возвращается в исходное положение. Какие-нибудь мысли? Я разместил вашу версию здесь, если вы хотите проверить, что я имею в виду: slug.directory/GX2 - person R-G; 21.04.2020

Я не смог получить доступ к вашему шрифту, поэтому вместо этого я использовал свойство css color!

Чтобы отслеживать конечную точку анимации, я использовал animationiteration событие в теле. Логика такова,

Если анимация завершается "нечетное количество циклов", измените color и animation-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>

Попробуйте вживую! (подробности см. в консоли)


Вам может быть интересно, почему я не использовал animationend прямо на body. Это связано с тем, что ваша анимация зацикливается бесконечно;)

person vrintle    schedule 18.04.2020
comment
@R-J: я удалил lastScroll, чтобы упростить задачу. Любая обратная связь? - person vrintle; 18.04.2020
comment
Мне нравится ваше мышление здесь, однако я не думаю, что это работает на практике. Я поместил ваш ответ здесь, чтобы проверить: slug.directory/GX3 Правильно ли я его реализовал? больше не крутится? Благодарность - person R-G; 21.04.2020
comment
@R-J: я не могу отлаживать скрипт на веб-сайте (пробовал журналы консоли, но это не сработало). Итак, вы хотите поделиться своим шрифтом, чтобы я мог отлаживать его локально? Это было бы полезно. - person vrintle; 21.04.2020
comment
Конечно, шрифт уже есть, если вы посмотрите в вы (с) знаете (с) что (с). С нетерпением жду результата :-) спасибо! - person R-G; 21.04.2020
comment
@R-J: я не понял конца твоего первого предложения. Я говорил, что вы указали относительный путь к вашему шрифту url('../fonts/AccidenzTestGX.ttf'), и, следовательно, я никогда не смогу получить доступ к вашему шрифту. Как сказать, что оно уже есть? - person vrintle; 22.04.2020