How come my dimensions are not returning correctly when I use offset().top and scrollTop() inside a scrolling element?

Currently in the process of developing a web app at , I am looking to implement a feature that will fade elements in and out as they enter and leave the visible part of a scrolling parent element. Taking inspiration from myfunkyside's response on this post Fade In on Scroll Down, Fade Out on Scroll Up - based on element position in window, I have incorporated a similar code snippet found here https://jsfiddle.net/tciprop/u4vaodvL/. However, I seem to be facing issues where either the offset top of the elements is too large or the visible area of the scrolling div is positioned too low, causing the fade effect to overlap into the visible region. Any insights or suggestions are welcome. Here is the link to my Fiddle: https://jsfiddle.net/tciprop/u4vaodvL/.

HTML

<div class="header"></div>
<div class="menu">
  <div class="fade">Fade In 01</div>
  <div class="fade">Fade In 02</div>
  <div class="fade">Fade In 03</div>
  <div class="fade">Fade In 04</div>
  <div class="fade">Fade In 05</div>
  <div class="fade">Fade In 06</div>
  <div class="fade">Fade In 07</div>
  <div class="fade">Fade In 08</div>
  <div class="fade">Fade In 09</div>
  <div class="fade">Fade In 10</div>
  <div class="fade">Fade In 01</div>
  <div class="fade">Fade In 02</div>
  <div class="fade">Fade In 03</div>
  <div class="fade">Fade In 04</div>
  <div class="fade">Fade In 05</div>
  <div class="fade">Fade In 06</div>
  <div class="fade">Fade In 07</div>
  <div class="fade">Fade In 08</div>
  <div class="fade">Fade In 09</div>
  <div class="fade">Fade In 10</div>
</div>

CSS

body {
  overflow-x: hidden;
  overflow-y: hidden;
}
.header {
  height: 40px;
}
.fade {
  position: relative;
  margin: 10px 5px 10px 5px;
  padding: 10px 5px 10px 5px;
  background-color: lightgreen;
  opacity: 1;
  height: 50px;
}
.menu {
  position: relative;
  overflow-x: hidden;
  overflow-y: scroll;
  border: 2vw 3vh;
    width: 90vw;
  height: 80vh;
  margin: auto;
}

JS

$(window).on("load",function() {
  $(".menu").scroll(function() {
    $(".fade").each(function() {
        //find relative positions
        var objectTop = $(this).offset().top;
        var objectBottom = objectTop + $(this).outerHeight();
        var windowTop = $(".menu").scrollTop();
        var windowBottom = windowTop + $(".menu").innerHeight();

      if (objectTop < windowTop) {//fade out on leaving top of scrollable area
            if ($(this).css("opacity")==1) {
                    $(this).fadeTo(500,0);
            }
      } else if (objectBottom < windowBottom && objectTop > windowTop) {//fade in on entering top of scrollable area
            if ($(this).css("opacity")==0) {
                    $(this).fadeTo(500,1);
          }
      } else if (objectBottom < windowBottom) {//fade in on entering bottom of scrollable area
            if ($(this).css("opacity")==0) {
                    $(this).fadeTo(500,1);
          }
      } else {
            if ($(this).css("opacity")==1) {//fade out on leaving bottom of scrollable area
                    $(this).fadeTo(500,0);
            }
      }
     console.log(objectTop, objectBottom, windowTop, windowBottom);
    });
  }); $(".menu").scroll(); //invoke scroll-handler on page-load
});

Answer №1

Swap .position().top for offset().top (Other modifications were implemented, see bullet points):

$(window).on("load",function() {
    $(".menu").scroll(function() {
        var parentBottom = $(this).innerHeight();
        $(".fade").each(function() {
            var objectTop = $(this).position().top;
            var objectBottom = objectTop + $(this).outerHeight();

            if (0 <= objectTop&&objectBottom < parentBottom) { //fade in when object is completely within view
                if ($(this).css("opacity")==0) {$(this).fadeTo(500,1);}
            } else { //fade out when object goes out of view (either top or bottom)
                if ($(this).css("opacity")==1) {$(this).fadeTo(500,0);}
            }
        });
    }).scroll(); //invoke scroll-handler on page-load
});

$(window).on("load",function() {
  $(".menu").scroll(function() {
    var parentBottom = $(this).innerHeight();
    $(".fade").each(function() {
      var objectTop = $(this).position().top;
      var objectBottom = objectTop + $(this).outerHeight();
      
      if (0 <= objectTop&&objectBottom < parentBottom) { //fade in when object is completely within view
        if ($(this).css("opacity")==0) {$(this).fadeTo(500,1);}
      } else { //fade out when object goes out of view (either top or bottom)
        if ($(this).css("opacity")==1) {$(this).fadeTo(500,0);}
      }
    });
  }).scroll(); //invoke scroll-handler on page-load
});
body {
  overflow-x: hidden;
  overflow-y: hidden;
}
.header {
  height: 40px;
  border: 2px solid red;
}
.menu {
  position: relative;
  width: 90vw;
  height: 80vh;
  margin: auto;
  border: 1px solid blue;
  border-width: 2vw 3vh;
  overflow-x: hidden;
  overflow-y: scroll;
}
.fade {
  position: relative;
  height: 50px;
  margin: 10px 5px;
  padding: 10px 5px;
  background-color: lightgreen;
  opacity: 1;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>

<div class="header"></div>
<div class="menu">
  <div class="fade">Fade In 01</div>
  <div class="fade">Fade In 02</div>
  <div class="fade">Fade In 03</div>
  <div class="fade">Fade In 04</div>
  <div class="fade">Fade In 05</div>
  <div class="fade">Fade In 06</div>
  <div class="fade">Fade In 07</div>
  <div class="fade">Fade In 08</div>
  <div class="fade">Fade In 09</div>
  <div class="fade">Fade In 10</div>
  <div class="fade">Fade In 11</div>
  <div class="fade">Fade In 12</div>
  <div class="fade">Fade In 13</div>
  <div class="fade">Fade In 14</div>
  <div class="fade">Fade In 15</div>
  <div class="fade">Fade In 16</div>
  <div class="fade">Fade In 17</div>
  <div class="fade">Fade In 18</div>
  <div class="fade">Fade In 19</div>
  <div class="fade">Fade In 20</div>
</div>
jsfiddle: https://jsfiddle.net/2bc5ueLc/3/

  • .scrollTop has been replaced with 0.
  • parentBottom (windowBottom) was moved outside the .each function to optimize performance.
  • The if-clause logic was simplified for better readability.

UPDATE

If you prefer to fade elements based on their visible percentage, utilize this code:

$(window).on("load",function() {
    $(".menu").scroll(function() {
        var parentBottom = $(this).innerHeight();
        $(".fade").each(function() {
            var objectHeight = $(this).outerHeight();
            var objectTop = $(this).position().top;
            var objectBottom = objectTop + objectHeight;

            //fade in/out based on visible percentage of element
            if (objectTop < 0) {
                if (objectBottom > 0) {$(this).fadeTo(0,objectBottom/objectHeight);}
                else if ($(this).css("opacity")!=0) {$(this).fadeTo(0,0);}
            } else if (objectBottom > parentBottom) {
                if (objectTop < parentBottom) {$(this).fadeTo(0,(parentBottom-objectTop)/objectHeight);}
                else if ($(this).css("opacity")!=0) {$(this).fadeTo(0,0);}
            } else if ($(this).css("opacity")!=1) {$(this).fadeTo(0,1);}
        });
    }).scroll(); //invoke scroll-handler on page-load
});

$(window).on("load",function() {
  $(".menu").scroll(function() {
    var parentBottom = $(this).innerHeight();
    $(".fade").each(function() {
      var objectHeight = $(this).outerHeight();
      var objectTop = $(this).position().top;
      var objectBottom = objectTop + objectHeight;
      
      //fade in/out based on visible percentage of element
      if (objectTop < 0) {
        if (objectBottom > 0) {$(this).fadeTo(0,objectBottom/objectHeight);}
        else if ($(this).css("opacity")!=0) {$(this).fadeTo(0,0);}
      } else if (objectBottom > parentBottom) {
        if (objectTop < parentBottom) {$(this).fadeTo(0,(parentBottom-objectTop)/objectHeight);}
        else if ($(this).css("opacity")!=0) {$(this).fadeTo(0,0);}
      } else if ($(this).css("opacity")!=1) {$(this).fadeTo(0,1);}
    });
  }).scroll(); //invoke scroll-handler on page-load
});
body {
  overflow-x: hidden;
  overflow-y: hidden;
}
.header {
  height: 40px;
  border: 2px solid red;
}
.menu {
  position: relative;
  width: 90vw;
  height: 80vh;
  margin: auto;
  border: 1px solid blue;
  border-width: 2vw 3vh;
  overflow-x: hidden;
  overflow-y: scroll;
}
.fade {
  position: relative;
  height: 50px;
  margin: 10px 5px;
  padding: 10px 5px;
  background-color: lightgreen;
  opacity: 1;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>

<div class="header"></div>
<div class="menu">
  <div class="fade">Fade In 01</div>
  <div class="fade">Fade In 02</div>
  <div class="fade">Fade In 03</div>
  <div class="fade">Fade In 04</div>
  <div class="fade">Fade In 05</div>
  <div class="fade">Fade In 06</div>
  <div class="fade">Fade In 07</div>
  <div class="fade">Fade In 08</div>
  <div class="fade">Fade In 09</div>
  <div class="fade">Fade In 10</div>
  <div class="fade">Fade In 11</div>
  <div class="fade">Fade In 12</div>
  <div class="fade">Fade In 13</div>
  <div class="fade">Fade In 14</div>
  <div class="fade">Fade In 15</div>
  <div class="fade">Fade In 16</div>
  <div class="fade">Fade In 17</div>
  <div class="fade">Fade In 18</div>
  <div class="fade">Fade In 19</div>
  <div class="fade">Fade In 20</div>
</div>
jsfiddle: https://jsfiddle.net/2bc5ueLc/6/

Answer №2

Revise this section of your code

var windowTop = $(".menu").scrollTop();
var windowBottom = windowTop + $(".menu").innerHeight();

replace .menu with window

var windowTop = $(window).scrollTop();
var windowBottom = windowTop + $(window).innerHeight();

$(window).on("load", function() {
  $(".menu").scroll(function() {
    $(".fade").each(function() {
      //find relative positions
      var objectTop = $(this).offset().top;
      var objectBottom = objectTop + $(this).outerHeight();
      var windowTop = $(window).scrollTop();
      var windowBottom = windowTop + $(window).innerHeight();

      if (objectTop < windowTop) { //fade out on leaving top of scrollable area
        if ($(this).css("opacity") == 1) {
          $(this).fadeTo(500, 0);
        }
      } else if (objectBottom < windowBottom && objectTop > windowTop) { //fade in on entering top of scrollable area
        if ($(this).css("opacity") == 0) {
          $(this).fadeTo(500, 1);
        }
      } else if (objectBottom < windowBottom) { //fade in on entering bottom of scrollable area
        if ($(this).css("opacity") == 0) {
          $(this).fadeTo(500, 1);
        }
      } else {
        if ($(this).css("opacity") == 1) { //fade out on leaving bottom of scrollable area
          $(this).fadeTo(500, 0);
        }
      }
      console.log(objectTop, objectBottom, windowTop, windowBottom);
    });
  });
  $(".menu").scroll(); //invoke scroll-handler on page-load
});
body {
  overflow-x: hidden;
  overflow-y: hidden;
}
.header {
  height: 40px;
}
.fade {
  position: relative;
  margin: 10px 5px 10px 5px;
  padding: 10px 5px 10px 5px;
  background-color: lightgreen;
  opacity: 1;
  height: 50px;
}
.menu {
  position: relative;
  overflow-x: hidden;
  overflow-y: scroll;
  border: 2vw 3vh;
  width: 90vw;
  height: 80vh;
  margin: auto;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="header"></div>
<div class="menu">
  <div class="fade">Fade In 01</div>
  <div class="fade">Fade In 02</div>
  <div class="fade">Fade In 03</div>
  <div class="fade">Fade In 04</div>
  <div class="fade">Fade In 05</div>
  <div class="fade">Fade In 06</div>
  <div class="fade">Fade In 07</div>
  <div class="fade">Fade In 08</div>
  <div class="fade">Fade In 09</div>
  <div class="fade">Fade In 10</div>
  <div class="fade">Fade In 01</div>
  <div class="fade">Fade In 02</div>
  <div class="fade">Fade In 03</div>
  <div class="fade">Fade In 04</div>
  <div class="fade">Fade In 05</div>
  <div class="fade">Fade In 06</div>
  <div class="fade">Fade In 07</div>
  <div class="fade">Fade In 08</div>
  <div class="fade">Fade In 09</div>
  <div class="fade">Fade In 10</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

Is it possible to prevent the selected option from being available in other select lists using AngularJS?

Can anyone help me figure out how to disable an option in one select list when it is selected in another using AngularJS? I have set up a select list for From Year and To Year with ng-repeat, which is working fine. Now, I just need to implement the functio ...

What are some ways to create a traditional HTML form submission and incorporate jQuery solely for the callbacks?

Given that my page consists solely of a simple "name and email" registration form, I see no reason why I shouldn't stick to the traditional approach: <form action="/Account/Register/" method="POST" id="registration-form"> <fields ...

Issues with zoom functionality not functioning properly within IE11

I am currently developing an application with Angular that is designed to be compatible with tablets and touch-enabled devices. One of the key features I want to implement is the ability for users to zoom/scale up the app, especially for those with visual ...

Utilizing strings as data in Google charts with jQuery

When working with google charts, the code for generating a chart often looks something like this: var data = new google.visualization.DataTable(); data.addColumn('string', 'Topping'); data.addColumn('number', 'Slices&apo ...

Key query when incorporating Jquery with PHP to create ajax requests

I'm facing a fundamental query regarding the use of jQuery with PHP for AJAX calls in terms of performance. Should I opt for a GET or a POST method? Which one provides faster results when making AJAX calls. Even though this question is not directly re ...

methods for transferring javascript variables to modal

<div> <h5> <a href="<?php echo base_url(); ?>/vendor/home/projects" >Return to Projects</a> </h5> <div> <div class="container"> <div class="row"> ...

Looking to align a radio button in the middle of an inline-block?

Is it possible to center a radio button within an inline-block? I have provided a demo on JSFiddle that displays the current layout and how I envision it should appear. Check out the demo here Here is the code snippet in question: <span style="widt ...

elements that do not adhere to set width constraints

I've successfully arranged elements in my HTML using flexbox to achieve a responsive design for a website. However, I've encountered an issue where the elements do not resize properly. After applying a class of flex to the home-promos div and re ...

Subheaders that stay in place while scrolling through a table with a stationary header

My goal is to design a table with a fixed header that allows the body to scroll under the header. While this is a common design, I am facing the challenge of implementing sticky subheaders. These subheaders should scroll along with the table until they rea ...

Styling a multilevel list with CSS that includes a combination of

Hello everyone! I am looking to create a mixed multilevel list in CSS, similar to the one shown in this image: image description here. I have attempted the following code snippet, but it seems to apply the counter to unordered lists: ol { counter-res ...

unable to connect with the server

I'm facing an issue with an ajax call. It seems to work perfectly when testing in the browser, but when using ajax, it doesn't get called. The URL causing trouble is: Upon checking in Firefox's inspect element console, after sending the req ...

How can I ensure that VueJS only starts loading data after the initial API call has been completed?

After retrieving data from an API, I populate a form in my component. The challenge I am facing is that the watchers are triggered immediately after populating the initial data. I want them to be triggered asynchronously. Additionally, I need to prevent th ...

"Utilizing JavaScript to filter JSON data at a deep nested

When working with a JSON data set, I often face the challenge of filtering based on specific child values. Take the following example: [ { "Date": "2017-03-02T00:00:00", "Matches": [ { "Id": 67, ...

Arrangement of components within an entity

I have an instance (let's refer to it as myObject) that is structured like this (when you log it to the console): >Object {info1: Object, info2: Object, info3: Object, info4: Object,…} >info1: Object >info2: Object Id: 53 ...

How to make Firefox create a new line in a contenteditable field

I am working with a contenteditable div that is within a parent div with a floating width of 50%. My goal is to set the max width of the content editable to match the container, even if the text spans multiple lines. Here is the CSS I tried: .editable-con ...

What is the best way to overlay an SVG line on top of a CSS style?

Is there a way to make SVG lines appear on top of CSS-styled elements in my HTML file? I have a white background SVG created with JavaScript using d3, and I am adding CSS-styled rectangles on top of it. However, I also want SVG lines (created with JavaScri ...

Creating a JSON data array for Highcharts visualization: rearranging values for xAxis and columns

I am facing an issue with my column chart where JSON data is being parsed in the "normal" form: Years are displayed on the xAxis and values on the yAxis (check out the fiddle here): array( array( "name" => "Bangladesh", ...

Accessing a specific element within an array that has been nested within another array, using JavaScript

Here's what my code looks like: planets[0]= new THREE.Mesh( geometry, material ); planettexts[0]= new THREE.Mesh( textGeometry, textMaterial ); planets[0].add(planettexts[0]); Now, I am trying to hide the planettext, but every attempt results in an ...

What are the steps to implement a horizontal scroll feature on a website when the scroll width is set to 0?

My goal is to enable users to scroll in the web view similar to how they can drag to scroll on mobile devices Check out my sandbox here for reference I have created a sample sandbox with the following code: <!DOCTYPE html> <html lang="en&qu ...

Unable to capture user input text using $watch in AngularJS when applied on ng-if condition

I have developed a cross-platform application using AngularJS, Monaca, and OnsenUI. In my login view, I check if the user has previously logged in by querying a SQLite database. Depending on whether there is data in the database, I either display a welcom ...