Count visible article tag in viewport based on responsive behaviour

Live link

This is the HTML edifice.
section has 9 article tags. Currently, through flexbox only 3 are visible, and on click when JS is written it will slide.

In dom there are 9 article, currently in browser viewport 3 are visible, but on the low viewport, 2 or 1 will be visible, based on the media queries. Is it possible through JS or some JS API to calculate in some JS variable how many article under the current viewport is visible?

<section>
	<article></article>
	<article></article>
	<article></article>
	<article></article>
	<article></article>
	<article></article>
	<article></article>
	<article></article>
	<article></article>
</section>

Another way to ask this question would be to know through JS how many article are currently visible in the viewport out of the total 9 article.

My antivirus software doesn’t want me to go to your web site, so I’ll hold off on looking, but…

This problem is the same as addressed by “lazy loading” of images, i.e. "is this image visible in the viewport or not? You can search for existing lazyloading tools, but essentially it’s a matter of using the getBoundingClientRect() (https://developer.mozilla.org/en-US/docs/Web/API/Element/getBoundingClientRect() ) function to get the position and coordinates of the box surrounding each of your articles, and comparing those coordinates to the box of your viewport to see if any portion of the article’s box is within.

1 Like

Thanks, and the site is opening properly here →

Do you mean visible in the viewport or visible inside your section element? I can’t quite get what you mean by “under the current viewport”.

Anyway why do you need to know this? Is this so you can slide the correct number of items each time?

If so are you going to use css media queries to change from 3 across to 2 across to 1 across when you want them to change? There doesn’t seem to be an automatic way to make this happen so I assume you are going to use media queries to do this and if so then you will know how many are in the viewport because you put them there :slight_smile:

If your JS needs to know so that you can slide one or two instead of three then as @tracknut said above you could just compare the article width against the parent elements width and work it out that way. That would seem to be the simplest method

It would also probably be quite easy to use matchmedia to change the js variable for the number of items if indeed you are changing the number of items in your media queries. Just as a test view the console in this demo. The benefit of matchmedia is that you don’t need to monitor the resize event to make your calculations.

Of course I may have completely misunderstood anyway :slight_smile:

1 Like

Hi there,
Sir, Visible in viewport.

Currently, this below controls the viewport →

.slider {
	display: flex;
	gap: 5%;
	justify-content: space-between;
	overflow: hidden;
}
article.commonclass {
	flex: 0 0 30%;
	margin: 70px auto;
}

In browser, it appears like this →

section: 9 article
viewport: 3 article visible in viewport

Now, let us say that at some other viewport width we change css:

.slider {
	display: flex;
	gap: 10%;
	justify-content: space-between;
	overflow: hidden;
}
article.commonclass {
	flex: 0 0 45%;
	margin: 70px auto;
}

45% + 45% + 10%(gap property) = 100% viewport width = Two elements visible in viewport

section: 9 article
viewport: 2 article visible in viewport

Furthermore at some other width of viewport or media query:

.slider {
	display: flex;
	justify-content: space-between;
	overflow: hidden;
}
article.commonclass {
	flex: 0 0 100%;
	margin: 70px auto;
}

section: 9 article
viewport: 1 article visible in viewport

In real life situation in full viewport width, there can be 4, and in other lesser viewport widths, there can be 3, 2, or 1 article visible in the viewport.

I have most of the things clear, but two challenges:

#1 →
In some var sectionArticleViewport = {some javascript code that will fetch total number of visible article in the viewport within that section}

#2 → I had a discussion with you on another post, which has a for next click like this →

const nextClick = document.querySelector(".next");
nextClick.addEventListener('click', event => {
	console.log("Yes Next Event Triggered");
	event.preventDefault();
	var noHoliday = document.querySelector("article.commonclass:not(.holidayclass)") && document.querySelector("article.commonclass:not(.holidayclass2)");
	var nSibling = noHoliday.nextElementSibling;
	if (nSibling.classList.contains("holidayclass")) {
		nSibling.classList.remove("holidayclass");
		noHoliday.classList.add("holidayclass2");	
		currentIndex = currentIndex + 1;
		document.querySelector(".currentslide").innerHTML = currentIndex;
	}
});

The second challenge is currently I am working on just nextElementSibling, →

nSibling.classList.remove("holidayclass");
noHoliday.classList.add("holidayclass2");

but later once I have this variable → var sectionArticleViewport based on that numeric I have to update classes in the next 3, 2, or 1 sibling based on the number of articles in the viewport that will be captured in → var sectionArticleViewport

Matchmedia concept is new to me let me have a look.

1 Like

I think I mentioned it before to you but I may be mis-remembering :slight_smile:

As another option you could use matchmedia as in my example and set the js variable based on which media was matched and then use that variable when your button is clicked. Assuming this is just a button click slider then you could instead store that value into a data attribute on the wrap in the html and then when a button is clicked you just look at the value in the data attribute on .wrap. This would save passing variables anywhere.

I suppose it all depends on what your final concept will be.

I know you want to write this yourself so I’ll leave you to play :slight_smile:

1 Like

Hi there,

I have come up with some version here. it works, but it has certain issues in logic that needs to be resolved.

When the sliding transaction reaches the finish point after click. The script slightly fails. when we click on previous.
It works well for 3n when the remainder is “0” but failed for

3n + 2 when the remainder is 2
3n + 1 when the remainder is 1

This is the JS →

const previousClick = document.querySelector(".previous");
previousClick.addEventListener('click', event => {
	console.log("Previous event clicked");
	event.preventDefault();
	var noHoliday = document.querySelectorAll("article.commonclass:not(.holidayclass,.holidayclass2)");
	console.log(noHoliday);
	var pSibling = noHoliday[0].previousElementSibling;
	if (pSibling.classList.contains("holidayclass2")) {
		for (let i = 0 ; i < viewportArticle; i++) {
			console.log(pSibling);
			noHoliday[i].classList.add("holidayclass");
			pSibling.classList.remove("holidayclass2");
			pSibling = pSibling.previousElementSibling;	
		}		
	}
});

I was able to fix this with a different logic →

var viewportArticle = 3; //Later it will be dynamic value based on DOM calculations

const nextClick = document.querySelector(".next");
nextClick.addEventListener('click', event => {
	console.log("Next event clicked");
	event.preventDefault();
	var nodeHolidayClass = document.querySelectorAll("article.holidayclass");
	var nodeCommonClass = document.querySelectorAll("article.commonclass:not(.holidayclass,.holidayclass2)");

	if (nodeCommonClass.length >= viewportArticle) {		
		for (let i = 0 ; i < viewportArticle; i++) { 
			nodeCommonClass[i].classList.add("holidayclass2");
		}
		for (let i = 0 ; i < viewportArticle; i++) { 
			nodeHolidayClass[i].classList.remove("holidayclass");
		}		
	}

});

const previousClick = document.querySelector(".previous");
previousClick.addEventListener('click', event => {
	console.log("Previous event clicked");
	event.preventDefault();
	var nodeHolidayClass2 = document.querySelectorAll("article.holidayclass2");
	var nodeCommonClass = document.querySelectorAll("article.commonclass:not(.holidayclass,.holidayclass2)");	
	for (let i = 1 ; i <= viewportArticle; i++) { 
		nodeHolidayClass2[nodeHolidayClass2.length-[i]].classList.remove("holidayclass2");
	}
	for (let i = 0 ; i < nodeCommonClass.length; i++) {
		nodeCommonClass[i].classList.add("holidayclass");
	}	
});

This addresses 3n+1, and 3n+2 issue → nodeCommonClass.length

New live link.

This topic was automatically closed 91 days after the last reply. New replies are no longer allowed.