Is it possible to determine which child element is currently in view within a scrollable parent div?

In an attempt to replicate a "current page" feature using divs, similar to a PDF reader.

document.addEventListener("DOMContentLoaded", function(event) {
  var container = document.getElementById("container");
  container.onscroll = function() {
    let position = container.scrollTop;
    let divs = document.querySelectorAll('.page');
    for (div of divs) {
      //???
    }
  }
});
#container {
  width: 400px;
  height: 600px;
  overflow: auto;
}

.page {
  width: 400px;
}

.red {
  background-color: red;
  height: 600px;
}

.blue {
  background-color: blue;
  height: 400px;
}
Current page: <span id="page-counter">1</span>
<div id='container'>
  <div id="div-1" class="page red"></div>
  <div id="div-2" class="page blue"></div>
  <div id="div-3" class="page red"></div>
  <div id="div-4" class="page blue"></div>
</div>

I'm seeking advice on how to dynamically update the page-counter span to display "3" when the third div is reached.

Something akin to this example: https://i.stack.imgur.com/9ppQd.png

Appreciate your help, Celso

Answer №1

In case you're wondering why this question wasn't tagged with jQuery, here's a JavaScript solution that mimics the desired behavior to the best of my knowledge. The solution calculates the visible pixels of each child element within the container. If it's equal to or greater than half the container size, it assumes that's the page your visitor is currently viewing.

function calculateVisibleHeight(element){
const container = document.getElementById("container");
let scrollTop = container.scrollTop;
let scrollBot = scrollTop + container.clientHeight;
let containerRect = container.getBoundingClientRect();
let eleRect = element.getBoundingClientRect();
let rect = {};
rect.top = eleRect.top - containerRect.top,
rect.right = eleRect.right - containerRect.right,
rect.bottom = eleRect.bottom - containerRect.bottom,
rect.left = eleRect.left - containerRect.left;
let eleTop = rect.top + scrollTop;
let eleBot = eleTop + element.offsetHeight;
let visibleTop = eleTop < scrollTop ? scrollTop : eleTop;
let visibleBot = eleBot > scrollBot ? scrollBot : eleBot;

return visibleBot - visibleTop;
}

document.addEventListener("DOMContentLoaded", function(event) {
const container = document.getElementById("container");
const divs = document.querySelectorAll('.page');

container.addEventListener("scroll", () => {
for(let i=0; i<divs.length; i++){
const containerHeight = container.clientHeight;

// Calculates the visible pixels within the container
let visiblePageHeight = calculateVisibleHeight(divs[i]);

// Sets the page if the visible pixel amount is at least half the container size
if(visiblePageHeight >= containerHeight / 2){
document.getElementById('page-counter').innerText = i+1;
}
}
}, false);
});
#container {
width: 400px;
height: 300px;
overflow: auto;
}

.page {
width: 380px;
}

.red {
background-color: red;
height: 300px;
}

.blue {
background-color: blue;
height: 200px;
}
Current page: <span id="page-counter">1</span>
<div id='container'>
<div id="div-1" class="page red"></div>
<div id="div-2" class="page blue"></div>
<div id="div-3" class="page red"></div>
<div id="div-4" class="page blue"></div>
</div>

Answer №2

One way to approach this is by creating a function that checks if an HTML element is visible within the viewport as the user scrolls. Below is an example using jQuery. While this may not be the most optimal method, it appears to work effectively. Try scrolling to see the IDs displayed.

function isInViewPort(element) {
  // This function checks if any part of the element is in the viewport.
  let $el = $("#" + element);
  let windowScrollTop = $(window).scrollTop();
  let windowHeight = $(window).height();
  let windowBottom = windowScrollTop + windowHeight;
  let elementTop = $el.offset().top;
  let elementOuterHeight = $el.outerHeight();
  let elementBottom = elementTop + elementOuterHeight;

  let isAboveViewPort = elementBottom < windowScrollTop;
  let isBelowViewPort = windowBottom < elementTop;

  return !(isAboveViewPort || isBelowViewPort);
}

let currentDiv;

$("#container").on("scroll", function() {
  $("#container").find("div").each(function() {
    if (isInViewPort(this.id) && currentDiv !== this.id) {
      $("#page").html("Current ID is " + this.id)
      currentDiv = this.id;
    }
  });
});
#container {
  overflow: auto;
  height: 300px;
}

.red {
  background-color: red;
  height: 600px;
}

.blue {
  background-color: blue;
  height: 400px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<span id="page"></span>
<div id='container'>
  <div id="div-1" class="page red"></div>
  <div id="div-2" class="page blue"></div>
  <div id="div-3" class="page red"></div>
  <div id="div-4" class="page blue"></div>
</div>

Answer №3

To determine if a div is visible using jQuery, assign each div a distinct ID or class.

if( $("#uniqueIdentifier").is(':visible'))
   $(".specificSelector").addClass('active');

To remove the active class, you can utilize an else statement to remove it from the inactive 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

Customized icons for Contact Form 7 on your Wordpress website

Currently, I am in the process of customizing a contact form by incorporating placeholder icons and text using the 'Contact Form 7' plugin within Wordpress. This particular contact form is situated on a website that I am constructing with the &ap ...

Enhancing the Strength of Password Generator

Example of a Simple Password Generator: function createPassword() { var characters = "abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOP" + "1234567890" + "@\#\-!$%^&*()_+|~=`{}\[\]:\";& ...

What is causing all Vuejs requests to fail in production with the error message "javascript enabled"?

My vuejs application interacts with a REST API in Node.js (Express, MongoDB Atlas). Everything runs smoothly when I run the Vue app on localhost while the Node.js app is on the server. However, when I deploy my dist folder to the server, although the app ...

Strange HTML pop-up keeps appearing every time I use styles in my code or insert anything with CSS

Recently, I created an OctoberCMS backend setup through my cPanel (I also have one on my localhost). Now, I am trying to add a background image but every time I attempt to do so, a strange HTML popup appears that I can't seem to figure out. Here is th ...

CSS - Nesting classes within one another

I'm currently working on customizing a Tumblr theme. Users have the option to choose between a one-column or two-column layout style, and I'm facing some challenges with implementing this in the CSS code. I attempted to add a class based on the u ...

Is it possible to implement sticky sessions with Node.js and pm2?

Can sticky sessions be implemented using the pm2 node module? Although not supported by Node.js's internal cluster module on purpose, it could still prove beneficial in scenarios like paused media streams. ...

Utilizing a CSS/HTML div grid to mirror a 2D array in JavaScript

Currently, I am working on a personal project that involves creating a grid of divs in HTML corresponding to a 2D array in JavaScript. However, I am uncertain about the most effective way to accomplish this task. Specifically, what I aim to achieve is tha ...

Ways to retrieve the path of a button found within table cells

https://i.stack.imgur.com/pUYHZ.jpgI'm currently working on a table where I've created a button that's being used in various rows and tables based on certain conditions. There's a specific scenario where I need to display the button for ...

Is it possible to alter the cursor according to the position of the mouse?

Is it possible to change the cursor from default to pointer when the mouse enters the specific rectangle area (50, 50, 100, 100) of the body? The dimensions are in pixels. Instead of defining a separate div and setting the cursor style on it, I'm loo ...

JavaScript: Adding up whole numbers--- Reference Error: Undefined

I'm having trouble with my code because it's saying that "t1" is not defined, even though it's the name of my text box. I tried making the variable global by declaring it outside the function, but it didn't solve the issue. Interestingl ...

Removing unexpected keys during validation using Joi

Within my server-side JavaScript code, I am utilizing Joi for validating a JavaScript object. The schema being used is structured as follows: var schema = Joi.object().keys({ displayName: Joi.string().required(), email: Joi.string().email(), e ...

How to programmatically update one input value in AngularJS and trigger validation as if it was manually entered by the user?

I'm currently using Angular 1.3.0rc2 and facing an issue with setting one input field based on another input field after the blur event. When I try to set the value of an input field that only has a synchronous validator, everything works fine by usi ...

AngularJS - Import and save CSV files

I have set up a nodeJS program as the server and an AngularJS web application as the client. For generating CSV files, I am utilizing the "express-csv" library (https://www.npmjs.com/package/express-csv) Below is the code for the server side: Definition ...

Easily modify and manage state on-the-fly using TextFields

Is the title conveying my intentions clearly? If not, please let me know. Essentially, I am looking to create a component that generates a form based on a JSON file. For example, if someone clicks on "light" in the navbar, I want the form to display fields ...

Unusual "visual" phenomenon with autocomplete feature in VUE.js

Can someone review this code snippet? Check out the code here This is a peculiar example of a custom autocomplete VUE component. If you enter a value in one of the fields in Section 1 (like 'Apple'), then click on the Next button, you'll ...

Populate a dropdown list with array elements using Javascript in ReactJS

I am encountering an issue while trying to populate a dropdown with data from the 'options' array. The error message states that it cannot read property appendChild of null. Using 'document.getElementByClassName' instead of document.ge ...

Nextjs couldn't locate the requested page

After creating a new Next.js application, I haven't made any changes to the code yet. However, when I try to run "npm run dev," it shows me the message "ready started server on [::]:3000, url: http://localhost:3000." But when I attempt to access it, I ...

How should h tags be correctly utilized?

Is it better to use h tags or lists to style content? Take a look at this code, is using h tags the appropriate choice here or should I consider using a list instead? <div class="col-xm-12 col-sm-6 col-md-4"> <h4>Get in touch< ...

The CSS styling for a pie chart does not seem to be functioning properly when using jQuery's

https://i.stack.imgur.com/kEAKC.png https://i.stack.imgur.com/03tHg.png After examining the two images above, it appears that the CSS is not functioning properly when I try to append the same HTML code using JavaScript. Below is the snippet of my HTML co ...

Storing data locally in Angular applications within the client-side environment

As I delve into Angular and TypeScript, I've encountered a perplexing issue. Let's say I have two classes - Employee and Department. On the server-side, I've established a Many-To-One relationship between these entities using Sequelize: db. ...