Struggling with smoothly transitioning an image into view using CSS and JavaScript

I'm currently experimenting with creating a cool effect on my website where an image fades in and moves up as the user scrolls it into view. I've included the code I have so far below, but unfortunately, I keep getting a 404 error when trying to run it. Any help would be greatly appreciated! I'm still new to JavaScript and have been working hard to understand this.

Check out my CSS:

.section3 {
        opacity: 0;
        transform: translateY(20vh);
        visibility: hidden;
        transition: opacity 0.6s ease-out, transform 1.2s ease-out;
        will-change: opacity, visibility;
    }
.fade {
        opacity: 1;
        transform: none;
        visibility: visible;
    }

Here is how the HTML and JS are structured:

<section id="section3" class="section3">
        <img style="width: 100%;" src="lovethyneighbor.jpg">
</section>

<script>
        var section3 = document.getElementById("section3");
        var location = section3.getBoundingClientRect();

        if (location.top >= 0) {
            document.getElementById("section3").classList.add("fade");
        } else {
            document.getElementById("section3").classList.add("section3");
        }
</script>

Answer №1

Let me introduce you to the Intersection Observer API! This handy tool is built into JavaScript and allows you to trigger an event or function when a specific element enters the viewport.

This API is a game-changer and I highly recommend using it over relying on getBoundingClientRect(). One of the main advantages is evident in the code snippet below:

if (location.top >= 0) {
     document.getElementById("section3").classList.add("fade");
} 
else {        
     document.getElementById("section3").classList.add("section3");
}

If you use Intersection Observer, your function will only run when needed, instead of being triggered by every mousewheel event, which can be inefficient and impact performance. With this API, your page is constantly monitored, and actions are only taken when elements come into view. Take a look at the annotated code below for further details.

Efficiency with Multiple Elements Requiring Different Animations

// Define the sections or containers
const sections = document.querySelectorAll("section.section");

// Set up options for the intersection function
const options = {
  root: null,
  threshold: 0.5, // Determine how much of the element should be visible before triggering the function (0 - 1)
  rootMargin: "0px 0px 0px 0px" // Default root margin value
};

// Initialize the observer - Allows multiple elements with varying animations to be tracked using forEach loop
let observer = new IntersectionObserver((entries) => {
  entries.forEach((entry) => {

    // Identify the element to animate
    const block = entry.target.querySelector("img.fader");

    // Retrieve all elements that need animation within the same section
    const animationBlocks = entry.target.querySelectorAll("[data-animation]");

    // Trigger animations when the element is visible
    if (entry.isIntersecting) {
      // Loop through multiple animations for the same element
      animationBlocks.forEach((animation) => {
        animationClass = animation.dataset.animation;

        // Apply data-animation class to initiate the animation
        animation.classList.add(animationClass);
      });
    }
  });
}, options);

observer.observe(document.querySelector("section.section"));

// Start running the animations
document.addEventListener("DOMContentLoaded", function() {
  Array.from(sections).forEach(function(element) {
    observer.observe(element);
  });
});
body {
  height: 300vh;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-direction: column;
  background-color: teal;
  gap: 400px;
}

/* Initial values */
[data-animation="fadeInUp"] {
  opacity: 0;
  transform: translate3d(0, 20px, 0);
}

/* Activate animation when class is added */
.fadeInUp {
  animation-name: fadeInUp;
  animation-duration: 0.6s;
  animation-fill-mode: both;
}

/* Animation definition */
@keyframes fadeInUp {
  from {
    opacity: 0;
    transform: translate3d(0, 20px, 0);
  }
  to {
    opacity: 1;
    transform: translate3d(0, 0, 0);
  }
}
<section id="section2" class="section section2">
  <img data-animation="fadeInUp" class="fader" style="width: 100%;" src="https://picsum.photos/200/300">
</section>

<section id="section3" class="section section3">
  <img data-animation="fadeInUp" class="fader" style="width: 100%;" src="https://picsum.photos/200/300">
</section>

Simplified Approach for Single Element and Single Animation

const sections = document.querySelectorAll("section.section");

const options = {
  root: null,
  threshold: 0.5
};

let observer = new IntersectionObserver((entries) => {
  entries.forEach((entry) => {

    const block = entry.target.querySelector("img.fader");

    if (entry.isIntersecting) {
      block.classList.add('fadeInUp');
    }
  });
}, options);

observer.observe(document.querySelector("section.section"));

// Begin running the animations
document.addEventListener("DOMContentLoaded", function() {
  Array.from(sections).forEach(function(element) {
    observer.observe(element);
  });
});
body {
  height: 300vh;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-direction: column;
  background-color: teal;
  gap: 400px;
}

img.fader {
  opacity: 0;
  transform: translate3d(0, 20px, 0);
}

.fadeInUp {
  animation-name: fadeInUp;
  animation-duration: 0.6s;
  animation-fill-mode: both;
}

@keyframes fadeInUp {
  from {
    opacity: 0;
    transform: translate3d(0, 20px, 0);
  }
  to {
    opacity: 1;
    transform: translate3d(0, 0, 0);
  }
}
<section id="section2" class="section section2">
  <img data-animation="fadeInUp" class="fader" style="width: 100%;" src="https://picsum.photos/200/300">
</section>

<section id="section3" class="section section3">
  <img class="fader" style="width: 100%;" src="https://picsum.photos/200/300">
</section>

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

What is the best way to collect and store data from various sources in an HTML interface to a Google Spreadsheet?

Currently, I have a spreadsheet with a button that is supposed to link to a function in my Google Apps Script called openInputDialog. The goal is for this button to open an HTML UI where users can input text into five fields. This input should then be adde ...

Discovering elements with Selenium through XPATH or CSS Selector

Having trouble locating the "import" element using Selenium Webdriver in C#. I've attempted the following codes but haven't had any luck: driver.FindElement(By.XPath("//*[@class='menu_bg']/ul/li[3]")).Click(); driver.FindElement(By.XPa ...

Error: The property 'postID' can not be read because it is undefined

I'm new to programming and I am working on creating a news/forum site as a practice project. I have set up a route /post/postID/postTitle to view individual posts. Initially, when I used only :postID, it worked fine. But after adding :postTitle, whene ...

I tried utilizing the wrapper feature, but unfortunately, the modal did

import React, { PropTypes } from 'react'; import Dialog from 'material-ui/Dialog'; export default class CustomModal extends React.Component { constructor(props){ super(props) } handlePrimaryButton = () => { this.prop ...

deleting the current product information during an ajax request

After executing the query provided below, I have $product_list in this code. However, I want to use ajax so that when I click on the button link1, $product_list gets emptied. How can I clear the content within products_list using an ajax call triggered by ...

An issue has been discovered with the Search function as JavaScript's Array.filter() and .map() methods are not functioning properly, resulting in

Currently, I'm working on integrating a search feature into my Flask application that will display the cities entered by users and are present in the JSON API results of a weather API. I am following a tutorial and have used a code similar to this: h ...

Using a jQuery UI accordion with a numbered list

As part of my company's user documentation, I am trying to integrate jQuery UI components into our HTML output. Despite my limited experience with JavaScript, I was able to get the accordion feature working for table rows. However, I am now facing dif ...

Angular is having trouble with the toggle menu button in the Bootstrap template

I recently integrated this template into my Angular project, which you can view at [. I copied the entire template code into my home.component.html file; everything seems to be working fine as the CSS is loading correctly and the layout matches the origina ...

Arrange the list by first names in the array using Ionic 3

What is the process for arranging a list by firstName from an array? This is my code in my.ts file: initializeItems(){ this.items = [ { avatar: '../../assets/imgs/profile1.jpg', firstName:'Sterlian', lastName:'Victorian ...

The call stack limit has been exceeded due to the combination of Node, Express, Angular, and Angular-route

Embarking on a new SPA journey, my tech stack includes: Back-end: NodeJS + Express Front-end: Angular + Angular-route. Twitter Bootstrap Underscore Having followed many tutorials with similar stacks, my project files are structured as follows: pac ...

Creating a CSV file using an AJAX request in PHP

In my current project involving PHP AJAX DATATABLE within the Drupal framework, I have successfully developed a function to create a CSV file from table records. This function is triggered by clicking a button in HTML or accessing a specific URL. The PHP ...

Struggling to log the values emitted from socket.io and express-nodejs

Having an issue with socket.io where the code is not emitting a value on a specific route. It works fine on the '/' route, but once I click submit and the route changes to '/process_post', I am unable to catch the emitted values by sock ...

Python script using selenium webdriver to interact with an accordion container and expand its contents (round

After successfully creating a scraper, I encountered an issue where the data I needed to scrape was hidden and required manual expansion before scraping. Upon inspecting the webpage source code, I found that the data was located within 3 different accordio ...

`What purpose does the data-view attribute serve in Durandal JS?`

While experimenting with the Durandal JS starter kit application, I happened to view the page source in Mozilla browser and noticed the following. <div class="" data-view="views/shell" style="" data-active-view="true"> </div> I couldn't ...

Guide to adding a file upload progress bar to your website

Is there a way to enhance file upload experience on my web application beyond the usual animated gif? I'm currently using .Net, but open to platform agnostic solutions as well. ...

When you choose the File->Print option, the PDF contents are seamlessly printed within the document

My web page has an embedded PDF file within the content. <h3>Foo</h3> <object id="foo" data="bigboundingbox.pdf" type="application/pdf" classid="clsid:CA8A9780-280D-11CF-A24D-444553540000"> </object> When viewed in Interne ...

The ID update functionality in Node.js is malfunctioning

Hello everyone, I am currently venturing into the world of NodeJS with a goal to create a backend API for a car rental agency. After writing some code to update, view, and delete records by id stored in MongoDB, I encountered a strange issue where it only ...

Ways to distinguish jquery response apart from using $.post method?

Using jquery $.post method: $.post( 'includes/studiesAjax/addTryb.php', {inputVL: inputVL}, function(res){ $("#container").html(res); } ); The response contains a long html code. I am interested in extracting data from ...

Craft a unique parallax effect using Framer Motion's clipping feature

To help visualize my concept, I have sketched it out using Figma. This idea involves a slide transitioning between pages. The goal is to cover the entire page with a sliding effect, and then place a sticker (dubbed the Parallax Box) on top of it. However ...

Removing an item from JSON data using Node.js and Express

Currently, I am attempting to remove an entry from json data. In order to view the data, I utilize the following: app.route('/data/:id') .get((req:Request, res: Response) => { let id = req.params.id; res.status(200).send(projects ...