What is the best way to animate an element when it comes into the user's view

In order to activate the animation of the skill-bars when the element is displayed on the website, I am seeking a solution where scrolling down through the section triggers the animation. Although I have managed to conceptualize and implement the idea with the assistance of codepen, there is a persistent issue that eludes my understanding. Essentially, I added a js file to initiate the animation upon viewing the element and incorporated the animate property in my CSS file for assigning the class whenever the element becomes visible. However, since multiple animations are present in the CSS file due to almost every class having an associated animation, it raises the question of how to consolidate all the element's animations under a single class called animate.

Code:

document.addEventListener("DOMContentLoaded", function(event) { 

// get the element to animate
var element = document.getElementById('box');

// listen for scroll event and call animate function
document.addEventListener('scroll', animate);

// check if element is in view
function inView() {
  var windowHeight = window.innerHeight;
  var scrollY = window.scrollY || window.pageYOffset;

  var scrollPosition = scrollY + windowHeight;
  var elementPosition = element.getBoundingClientRect().top + scrollY;

  if (scrollPosition > elementPosition) {
    return true;
  }

  return false;
}

function animate() {
  if (inView()) {
      element.classList.add('animate');
  }
}
});
@import url('https://fonts.googleapis.com/css2?family=Poppins:wght@200;300;400;500;600;700&display=swap');
*{
  margin: 0;
  padding: 0;
  box-sizing: border-box;
  font-family: 'Poppins', sans-serif;
}
body20{
  height: 100%;
  place-items: center;
  background: transparent;
}
::selection{
  color: #fff;
  background: black;
}
.skill-bars{
  padding: 25px 30px;
  width: 97%;
  background: #fff;
  box-shadow: 5px 5px 20px rgba(0,0,0,0.2);
  border-radius: 10px;
}
...

<section>
  <div class="container" data-aos="fade-up">
    <div class="section-title">
      <h2>What I am Working On</h2>
    </div>
    <link rel="stylesheet" href="assets/css/picturealign.css"> 
    <div class="column1">
      <div class="row1">
        <div class="skill-bars">
          <div class="bar">
            <div class="info">
              <span18>Harvard CS50 Course</span18>
            </div>
            <div class="progress-line html">
              <span18></span18>
            </div>
          </div>
          ...
        </div>
     </div>
  </div>
</section>

Answer №1

Are you interested in trying something like this out?

https://example.com/unique-link

    window.addEventListener("scroll", function() {
  elementsToShow.forEach(function(element) {
    var viewTop = window.pageYOffset;
    var viewBottom = (window.pageYOffset + window.innerHeight);
    var elementTop = element.offsetTop;
    var elementHeight = element.offsetHeight;
    
    if (viewBottom > elementTop && ((viewTop - elementHeight) < elementTop)) {
     element.classList.add("visible");
    } else {
      element.classList.remove("visible");
    }
  });
}, false);

Answer №2

The existing code is unable to detect when elements are scrolled in or out of view because it tries to target an element, 'box', that does not exist. Consequently, the animations only run once on each span18 element.

A more effective approach to determine if an element is within the viewport is to implement an intersectionObserver. This will execute a code block when an element enters or exits the view, eliminating the need for manual calculations.

Additionally, I've introduced a class called 'animated' which is added to a span18 element upon entering the view, and removed once it leaves the view. Without this, the animation would occur only once, and if the element is initially out of view, the user may never witness it.

document.addEventListener("DOMContentLoaded", function(event) {

// THIS FUNCTION WILL BE TRIGGERED WHEN A SPAN18 ELEMENT (OR ELEMENTS) ENTER OR LEAVE THE VIEW
      function callback (observations, observer) {
        observations.forEach(observation => {
          if (observation.isIntersecting) { //IF IT'S IN VIEW
            observation.target.classList.add('animated');
          }
          else {
            observation.target.classList.remove('animated');
          }      
       });
     }
      
      // SET UP AN INTERSECTION OBSERVER
      let options = {
         root: null, //null means it will observe on the viewport
         rootMargin: '0px',
         threshold: 1.0 //1 means the whole element needs to be viewable before we animate it
      }

      let observer = new IntersectionObserver(callback, options);
      
      // ADD THE OBSERVER TO EACH OF THE ELEMENTS WE WANT TO ANIMATE WHEN THEY ARE IN VIEW
      let spans = document.querySelectorAll('span18');
      for (let i=0; i< spans.length; i++) {
        observer.observe(spans[i]); 
      }
});
@import url('https://fonts.googleapis.com/css2?family=Poppins:wght@200;300;400;500;600;700&display=swap');
*{
  margin: 0;
  padding: 0;
  box-sizing: border-box;
  font-family: 'Poppins', sans-serif;
}
body20{
  height: 100%;
  place-items: center;
  background: transparent;
}
::selection{
  color: #fff;
  background: black;
}
.skill-bars{
  padding: 25px 30px;
  width: 97%;
  background: #fff;
  box-shadow: 5px 5px 20px rgba(0,0,0,0.2);
  border-radius: 10px;
}
.skill-bars .bar{
  margin: 20px 0;
}
.skill-bars .bar:first-child{
  margin-top: 0px;
}
.skill-bars .bar .info{
  margin-bottom: 5px;
}
.skill-bars .bar .info span18{
  font-weight: 500;
  font-size: 17px;
  opacity: 0;
  animation: showText 0.5s 1s linear forwards;
}
.animate{ /* This is the animation class */

}
@keyframes showText {
  100%{
    opacity: 1;
  }
}
.skill-bars .bar .progress-line{
  height: 10px;
  width: 100%;
  background: #f0f0f0;
  position: relative;
  transform: scaleX(0);
  transform-origin: left;
  border-radius: 10px;
  box-shadow: inset 0 1px 1px rgba(0,0,0,0.05),
              0 1px rgba(255,255,255,0.8);
                animation: animate 1s cubic-bezier(1,0,0.5,1) forwards; 

}
@keyframes animate {
  100%{
    transform: scaleX(1);
  }
}

.bar .progress-line span18{
  height: 100%;
  position: absolute;
  border-radius: 10px;
  transform: scaleX(0);
  transform-origin: left;
  background: black;
}
/* APPLY ANIMATED CLASS FOR ANIMATION */
.bar .progress-line span18.animated{
  animation: animate 1s 1s cubic-bezier(1,0,0.5,1) forwards;
}
.bar .progress-line.html span18{
  width: 84%;
}
.bar .progress-line.css span18{
  width: 76%;
}
.bar .progress-line.jquery span18{
  width: 91%;
}
.bar .progress-line.python span18{
  width: 59%;
}
.bar .progress-line.mysql span18{
  width: 70%;
}
/* ADDED ANIMATION TO OCCUR ONLY IN THE VIEWPORT */
.progress-line span18.animated::before{
  position: absolute;
  content: "";
  top: -10px;
  right: 0;
  height: 0;
  width: 0;
  border: 7px solid transparent;
  border-bottom-width: 0px;
  border-right-width: 0px;
  border-top-color: #000;
  opacity: 0;
  animation: showText2 0.5s 1.5s linear forwards;
}
.progress-line span18.animated::after{
  position: absolute;
  top: -28px;
  right: 0;
  font-weight: 500;
  background: #000;
  color: #fff;
  padding: 1px 8px;
  font-size: 12px;
  border-radius: 3px;
  opacity: 0;
  animation: showText2 0.5s 1.5s linear forwards;
}
@keyframes showText2 {
  100%{
    opacity: 1;
  }
}
.progress-line.html span18::after{
  content: "84%";
}
.progress-line.css span18::after{
  content: "76%";
}
.progress-line.jquery span18::after{
  content: "91%";
}
.progress-line.python span18::after{
  content: "59%";
}
.progress-line.mysql span18::after{
  content: "70%";
}
<div style="height: 100vh; width: 100vw; position: relative; background-color: cyan;"><div style="position: relative; top: 50vh; text-align: center;">SCROLL DOWN AND UP TO SEE THE ANIMATION EFFECTS</div></div>
<section>
        <div class="container" data-aos="fade-up">
      <div class="section-title">
        <h2>What I am Working On</h2>
        </div>
    <link rel="stylesheet" href="assets/css/picturealign.css"> 
      <div class="column1">
      <div class="row1">
  <div class="skill-bars">
    <div class="bar">
      <div class="info">
        <span18>Harvard CS50 Course</span18>
      </div>
      <div class="progress-line html">
        <span18></span18>
      </div>
    </div>
    <div class="bar">
      <div class="info">
        <span18>Youtube Channel (Java Tutorials)</span18>
      </div>
      <div class="progress-line css">
        <span18></span18>
      </div>
    </div>
    <div class="bar">
      <div class="info">
        <span18>C++</span18>
      </div>
      <div class="progress-line jquery">
        <span18></span18>
      </div>
    </div>
    <div class="bar">
      <div class="info">
        <span18>Java</span18>
      </div>
      <div class="progress-line python">
        <span18></span18>
      </div>
    </div>
    <div class="bar">
      <div class="info">
        <span18>Web Development (Front-End)</span18>
      </div>
      <div class="progress-line mysql">
        <span18></span18>
      </div>
    </div>
  </div>
            </div>
      </div>
      </div>

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

Enable scrolling exclusively for the content within a tab, without affecting the tab label in Clarity Tabs

I have a tab with lengthy content in my project (check out the StackBlitz reference here). This causes the appearance of a scroll. The corresponding code snippet is provided below: <div class="content-container"> <div class=&qu ...

Fetching server-side data for isomorphic React app: A guide to accessing cookies

Currently, I am in the process of developing an isomorphic/universal React + Redux + Express application. The method I use for server-side data fetching is quite standard: I identify the routes that match the URL, call the appropriate data-fetching functio ...

Creating a Stylish CSS Table Utilizing DIV Elements: Preventing the Top Row from Scrolling

Utilizing a pure DIV table with the display: table, table-row, table-cell format for styling, I have managed to make the entire table scroll except for the header row. However, I am in search of methods that can prevent the header row (1st row) from scroll ...

Utilizing a universal JavaScript array within the jQuery document(ready) function

After using jsRender to render the following HTML template, I encountered an issue with passing data values through jQuery selectors when submitting a form via AJAX. <div class="noteActions top" style="z-index: 3;"> <span onclick="noteAction(&a ...

Positioning a sticky footer in a dual-column design

This updated post is a revised version of the one found at this link. I aim to provide a clearer explanation of my issue compared to the previous post. The problem revolves around the placement of the footer in two different scenarios. Scenario 1: The fi ...

When an AJAX request is made, it can either return an array or a single object, potentially leading to

My proficiency in Javascript is definitely lacking, and I've only just begun to understand it. I have set up an AJAX call to an API using the GET method. The JSON data returned by the API is pretty standard. If I don't include an ID, I receive ...

Extract and loop through JSON data containing various headers

Having no issues iterating through a simple JSON loop, however, the API I am currently utilizing returns a response with multiple headers. Despite my efforts in various methods to access the results objects, I still face some challenges. The response struc ...

Executing a controller method in Grails using JavaScript

When working in a Grails view, I find myself needing to execute a JavaScript method to retrieve certain information. To achieve this, I have set up a submit action as shown below: <input type="submit" name="submit" class="submit action-button" value="G ...

The functionality of Angular 5 reactive form valueChanges is not functioning correctly

I am currently working with a form inside a service: this.settingsForm = this.formBuilder.group({ names: this.formBuilder.array([]), globalIDs: this.formBuilder.array([]), topics: this.formBuilder.array([]), emails: thi ...

Error message: "When using Webpack 4 with Bootstrap, a TypeError occurs where property 'jquery' is read as undefined."

I've recently delved into the world of webpack and everything seems to be running smoothly. However, when I run my webpack app, I encounter the following error within Bootstrap: var version = $.fn.jquery.split(' ')[0].split('.'); ...

Looking to extract a Twitter handle using Python's BeautifulSoup module?

I'm struggling to extract the Twitter profile name from a given profile URL using Beautiful Soup in Python. No matter what HTML tags I try, I can't seem to retrieve the name. What specific HTML tags should I be using to successfully grab the prof ...

Tips for combining all included files into one with Babel

My current project involves the use of Babel. Within my server.js file, I have the following line of code: import schema from "./data/schema"; The issue arises because data/schema.js is written in ES2015 syntax. After attempting to compile my server.js ...

Nested React Components in React Router Components

class AppRoutes extends Component { render () { return ( <Suspense fallback={<Spinner/>}> <Switch> <Route exact path="/" component={ HomePage } /> <Route exact path="/acti ...

Tips on choosing additional (sibling) elements with CSS?

My navbar has the following structure: <ul class="nav navbar-nav"> <li class="nav-item"><a href="#services">Services</a></li> <li class="nav-item"><a href="#work">Work</a></li> <li class ...

Exploring Javascript/JQuery parameters based on data types

I'm a bit confused about whether the title accurately reflects my question. I need help understanding how jQuery deals with functions that are called with different argument combinations, such as ("Some String", true, function(){}) and ("Some String", ...

Create a customized menu with jQuery that disappears when hovered over

Check out this menu I've created: http://jsbin.com/useqa4/3 The hover effect seems to be working fine, but I'm looking to hide the div #submenuSolutions when the user's cursor is not on the "Solution" item or the submenu. Is there a way to ...

interaction & portal

I am currently managing a website that includes an iframe. Both the main site and the embedded site within the iframe are verifying the $_SESSION["login"]. Therefore, if the session expires, the user will be automatically logged out. The issue I'm fa ...

Enhancing speed on an extensive list without a set height/eliminating the need for virtualization

My webapp includes a feature that showcases exhibitors at an expo. The user can click on "Exhibitors" in the navigation bar to access a page displaying all the exhibitors. Each exhibitor may have different details, some of which may or may not contain data ...

Personalize the position of the v-select drop-down menu

I am currently working with the vuetify v-select component. The problem I am encountering is that instead of the dropdown opening downwards, I need it to open upwards since the dropdown is positioned at the bottom of the page which causes some of the dro ...

Performing an axios request using form data in a React JS application

I am trying to figure out how to use axios in react js to make a cURL request that is currently working. Here is the cURL request: curl -k --request GET "BASE_URL_SERVER/sendText" --form "user_id='uidxxxx'" --form "sign_id=" Every time I try to ...