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

Issues with displaying images in CSS when using HTML 5 canvas drawing

In attempting to draw an image on a canvas using a pre-loaded image and CSS, such as: img.style.backgroundColor="red"; ctx.drawImage(img,0,0,100,100); I have observed that the image is drawn without incorporating the CSS modifications. Are HTML canvases ...

What is the best way to verify the number of values stored within a variable in JavaScript?

My goal is to calculate the sum of 6 values by inputting them into a single field using a button. To achieve this, I am seeking knowledge on how to determine the number of values contained within a variable. This will allow me to implement an "if" conditi ...

Exploring the Uses of SystemJS with TypeScript Loader

Can someone help clarify something about this TypeScript plugin for SystemJS? https://github.com/frankwallis/plugin-typescript/ Here is what the plugin does: This SystemJS plugin allows you to import TypeScript files directly and have them compiled in ...

Obtain a Compilation of Video Sources in an HTML5 Format

Hey there, I am using an HTML5 video. This is just an example <video width="320" id="video" height="240" controls> <source src="video.mp4" type="video/mp4"> <source src="video1.mp4" type="video/mp4"> <source src="movie.ogg" typ ...

Having trouble getting my JavaScript code to function properly on Firefox browser

I have created a script where the cursor automatically moves to the next form field once it reaches its maximum length, in this case 1. Here is the JavaScript code: window.onload=function(){ var container = document.getElementsByClassName("container")[0] ...

React Modals: Only the modal component triggered by the first click will open, with no other modals opening

As a newcomer to StackOverflow, I apologize if my problem description is not clear. I am currently learning React and working on a course-search app as a project. The app filters courses based on user input from a JSON file and displays them in cards with ...

When you call setTimeout from a static function, it does not get executed

Having a problem with starting a timer in my utility typescript class. The static function initTimer() uses setTimeout but when called from a react component, the timer doesn't start. StyleWrapper.tsx const StyleWrapper: FC = (props) => { cons ...

Managing modules within the node_modules folder that have dependencies on .css files

Currently, I am involved in a project where we are utilizing a custom UI library that includes some dependencies. These components come with their own corresponding .css files. The structure of the source code looks like this: |- src |-| |- components ...

Concatenate a variable string with the JSON object key

I am currently working on a request with a JSON Object structure similar to the following: let formData = { name: classifierName, fire_positive_examples: { value: decodedPositiveExample, options: { filename: 'posit ...

How can I dive into a nested array to access the properties of an object within?

My array, called sportPromise, is structured like this: 0: Array[0] 1: Array[1] 2: Array[2] 3: Array[3] When I run console.log(angular.toJson($scope.sportPromise, 'pretty'));, the output looks like this: [ [], [ { "id": 5932, ...

Is there a more efficient method to gather properties from an object into separate arrays without the need for using `map` twice?

Currently, my code block looks like this: res.json({ dates: rows.map(function (item) { return item.Date }), counts: rows.map(function (item) { return item.NewMembers }) }); While functional, I can't help but feel it is inefficient as the row ...

Guide on displaying a document in react-doc-viewer from a protected API endpoint in either Next.Js or ReactJs

I am looking to display files in my Next.JS web application using a secure API. The API provides the following data: { "name": "Test1.docx", "contentUri": "https://api.mypurecloud.ie/api/v2/downloads/x ...

Encountering unanticipated undefined elements while incorporating map in JSX

I'm attempting to dynamically generate <Audio> components using the map method: import React, { useState, useRef, createRef } from 'react'; const audios = [{ src: '/fire.mp3' }, { src: '/crickets.mp3' }]; function ...

Increasing values in Mongoose using $inc can be done by following these steps

I've been struggling to increment a field value using $inc in my code. My schema looks like this: var postSchema = mongoose.Schema({ title : { type: String, required: true }, body : { type: String, default: '' }, coun ...

Is there a way to determine the number of clicks on something?

I'm attempting to track the number of times a click event occurs. What is the best method to achieve this? There are two elements present on the page and I need to monitor clicks on both of them. The pseudo-code I have in mind looks something like ...

Troubleshooting in WebStorm: Uncovering the Root Cause Within an npm Package (node:36378) [DEP0005] - Warning: Deprecation Warning

Over the past 6 months, I've been encountering an error that seems to have surfaced after an update to node.js. (node:36378) [DEP0005] DeprecationWarning: Buffer() is deprecated due to security and usability issues. Please use the Buffer.alloc(), ...

Refine your search with a JSON object description in expressJS and UnderscoreJS

[ { "id": 1, "description": "Empty the garbage bin", "completed": false }, { "id": 2, "description": "Dine out for dinner", "completed": false }, { "id": 3, "description": "Exercise at the fitness center", "com ...

Switching React Icons when Clicked

I'm struggling to understand this. I want the React icons below to be filled and remain filled when clicked, changing back to outlined when another is clicked. Here's the code: import { useState } from "react"; import { Link } from "react-router- ...

What is the proper method for transforming an Excel column containing JSON format data into a JavaScript object?

I am facing an issue with converting data from an excel sheet to json format. While the other columns convert successfully, one specific column containing json data is not being converted properly and instead gets treated as a string. Using JSON.parse() on ...

-moz-box-reflect - Styling for FireFox

I've been attempting to achieve a similar effect to this tutorial at http://designshack.net/tutorialexamples/HoverEffects/Ex5.html. However, I'm encountering issues with getting the reflection of the image to display properly in IE and Firefox. H ...