What is the best way to activate an @keyframe animation based on the scrolling action?

I am currently working on an @keyframe animation that rotates a circle along its x-axis, starting from 0 degrees to 90 degrees and then back to 0 degrees. My objective is to synchronize the rotation of the circle with the user's scrolling movement on the page. The rotation should gradually increase in pace as the user scrolls down, reaching its peak at 90 degrees when the scroll count hits 160 down the page. After that, as the user continues to scroll beyond 160, I aim for the circle to incrementally rotate back to 0 degrees once they reach 280 down the page.

My initial approach involved placing the @keyframes within a class called Animation and attempting to trigger it using classList.add in JavaScript. However, this method did not yield the desired results.

If anyone has any insights or solutions to offer, I would greatly appreciate the assistance. Preferably, I am looking for a JavaScript-based solution without relying on jQuery.

function Ani(){
  Ani.classList.add('Animation');  
}
* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}
section{
  height: 100vh;
}
html, body {
  height: 100%;
}
.one{
  background-color: rgb(105, 170, 254);
}
#divItem {
  display: flex;
  justify-content: center;
  align-items: center;
  height: 100%;
  width: 100%;
  position: relative;
}

.triangle, .circle, .rectangle {
  position: absolute;
}

.circle {
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  margin: auto;
  animation: moving;
  animation-duration: 2s;
}

.Animation{
@keyframes moving {
  0%{
    transform:rotateX(0deg);
    transform-origin: 30% 50%;
  }
  50%{
    transform:rotateX(90deg);
    transform-origin: 30% 50%;
  }
  100%{
    transform: rotateX(0deg);
  }
}
}

.two{
  background-color: brown;
}
three{
  background-color: bisque;
}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Scroll-Trigger</title>
    <link rel="stylesheet" href="style.css">
</head>
<body>
  <section class="one">

<div id="divItem">
   
    <img src="triangle.svg" class="triangle" width="150px" />
    <div class="Animation">
    <img src="circle.svg" class = "circle" width="150px"/>
  </div>
    <img src="rectangle.svg" class="rectangle" width="150px"/> 
</div>

</section>  
<section class="two">
   
</section>

<section class="three">
  
</section>
<script src="index.js"></script>

</body>
</html>

Answer №1

If you're up for a challenge and prefer not to use keyframes, an alternative method to achieve your goal is by setting the rotation of your element to correspond with the scrollY of the page.

<div class="page">
  <div id="spinner"></div>
</div>
<script>
const handle = document.getElementById('spinner');
addEventListener('scroll', matchSpin);
function matchSpin () {
  let calc;
  if (scrollY < 160) {
    calc = scrollY  / (160 / 90)
  } else {
    calc = 90 - ((scrollY - 160) / (160 / 90))
  }
    handle.style.transform = `rotate(${calc}deg`;
}
</script>
.page {
  height: calc(320px + 100vh);
}

#spinner {
  position: fixed;
  left: calc(50vw - 35px);
  top: calc(50vh - 35px);
  height: 70px;
  width: 70px;
  background: red;
  transform: rotate(0deg);
}

Unfortunately, I'm unable to provide a code snippet at the moment but here's a link to a demo on JSFiddle.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Utilize the parsing functionality in three.js to extract JSON geometry data

After exporting a model from Blender using the three.js exporter and successfully loading it with the JSONLoader, my next challenge is to store the JSON information in a variable and parse it to display the model without having to load an external file. T ...

Specify a preset selection time in a TextField of time type in Material UI

I am looking to establish a default time for a textfield of type time in Material UI. My requirement is that before the user clicks on the picker, no time should be pre-set, but once they click, 08:00 should appear as the default time to choose from. View ...

What is the best way to configure AngularJS for optimal integration with Google Maps services and functionalities in an "angular way"?

I'm currently working on a new app that utilizes the Google distance matrix, directions service, and various map features such as custom markers. I'm curious - where do you think is the best place to house all of this different functionality? Sho ...

I want to set a single background image for all slides in fullPage.js. How can I achieve this

I am attempting to replicate a similar effect as shown in this example: The demonstration above utilizes the fullPage.js plugin. You may have noticed how the background image remains consistent while navigating through different sections. I have searched ...

What is the best way to ensure that an input group expands to fill the entire horizontal space

I am currently utilizing bootstrap 4 and have a responsive navbar for smaller screens. On this navbar, I am trying to implement a search input group that spans the full width from left to right up until the menu bar icon on the right side. You can view my ...

The selected plugin appears to be incompatible with mobile browsers

My project involves implementing the Chosen plugin for a select field, allowing users to type-search through lengthy lists. It functions perfectly on desktop but is disabled on both Apple and Android phones, reverting to the default user interface for sele ...

Accessing the 'comment' property within the .then() function is not possible if it is undefined

Why does obj[i] become undefined inside the .then() function? obj = [{'id': 1, 'name': 'john', 'age': '22', 'group': 'grA'}, {'id': 2, 'name': 'mike', &apo ...

What is the process for adding the multiple attribute to a select dropdown in a form?

I implemented the selectric plugin for dropdowns on my website. I included the multiple attribute in the select tag, but it doesn't seem to be functioning properly based on what is shown on the index page of the selectric plugin located at: This is t ...

Animate the React Bootstrap modal only when it is shown or hidden

I am experimenting with the idea of transitioning smoothly from one modal to another in bootstrap Modals for react (using react-bootstrap). However, I am facing challenges due to the fade CSS class causing flickers and unwanted animations. My goal is to h ...

Adding a unique object to a different user class with cloud code on Parse.com

I need to incorporate the current user object ID array into a user's "followers" column in Parse, but because of security restrictions, I have to use cloud code. Unfortunately, I don't know much about JavaScript and could use some assistance. Her ...

"Converting a database table record into a JavaScript array: Step-by-step guide

I'm currently expanding my knowledge of PHP by working on a small project. Within my database, I have a table called city_name which consists of columns for id, name, longitude, and latitude. Typically, this table contains around 10-15 rows. When a us ...

Is there a way to differentiate between a browser application running on a local development server and an online staging server?

Is there a way to conditionally call a component only on the staging server and not on the local machine in Vue.js? <save-drafts-timer v-if="!environment === 'development'" /> ... data () { return { environment ...

Is it possible to devise a universal click handler in TypeScript that will consistently execute after all other click handlers?

In my ReactJS based application written in TypeScript, we have implemented various click handlers. Different teams contribute to the application and can add their own handlers as well. The challenge we face is ensuring that a specific global click handler ...

Adding a blank data-columns attribute using jQuery:

I am trying to add the data-columns attribute for salvattore.js, but I am facing an issue where I cannot simply add the attribute without providing a value. Currently, my code looks like this: $('#liste-vdl div.view-content').attr("data-columns" ...

Perform an action when a key is held down and when it is released

I am looking to implement a function that needs to be called under certain conditions: It should be triggered every second while a key is being held down (for example, if the key is held down for five seconds, it should fire 5 times every second). If ...

Console displaying message of comfort twice - ReactJS

I have a simple app that increments the count from 10 to 11 in the componentDidMount life cycle, but for some reason, the numbers 10 and 11 are appearing twice in the console. I would like to understand why this is happening. Here is the code snippet: im ...

CSS following a clicked event

http://codepen.io/anon/pen/GqmEAq My goal is to make the 'x' button clicked (the 'x' is created after clicking the plus sign on the menu) and then bring the dropdown back up. I have attempted: a:after:checked ~ .submenu{ max-height ...

Seeking to have text spill over into a different container

Novice in CSS seeks advice. I've nailed the layout of the home page for my website with two divs</p> <p><div> <div> <pre class="snippet-code-css lang-css"><code>#desktop-navbar { text-transform: uppercase; ...

Restricting href Usage Based on Session

I find myself in a challenging situation without a clear solution at hand. Within this code, I am utilizing a link and a button for which I need to save the page in a database. Therefore, creating a server control is not an option as it will not be render ...

What causes the discrepancy in CSS display between production and development environments in Material-UI?

Using material UI (verison: ^4.12.3) Select, with a customized input has led to an unexpected issue in the production environment. The Select input in prod has a black background and a :before element with a white background that I didn't intend to ha ...