Scroll above element height + content change - javascript

I have looked around to see if this has been covered, but no dice.
I'm building a website using HTML5, CSS3 (+ animations), bootstrap, Vanilla JS and jQuery. The behavior I'm looking to induce for the site is one where a user visits a landing page and the scroll bar is situated at the top. Then, upon scrolling down past a certain point, a completely different screen takes over.
Here's the (maybe) tricky part:
I want for a visitor to be able to scroll all the way up on this 2nd screen as high as the scrollbar can go. Only once the scroll bar is at the top and they try try to scroll up past the top of the current window, that the original, first screen comes back in to play (while still persisting the progress they made on the 2nd screen if they decide to scroll back down).
Negative scrollTop/browser/window heights to trigger an event in which a user can navigate between pages using a maxed out up-top scrollbar? (& should I use a framework?) Much appreciated!

You could duplicate elements while scrolling,
I made a plunker to give you an idea
jQDocument.on("scroll", () => {
if(jQDocument.scrollTop() < 200) {
//Duplicate elements on top while scrolling up
let topScreen = detectTopScreen()
let indexTopScreen = getIndex(topScreen)
let screenIndexToDuplicate
if(indexTopScreen > 0) {
screenIndexToDuplicate = indexTopScreen - 1
} else {
screenIndexToDuplicate = maxIndex
}
let screenToPrepend = originalLoopDiv.children().eq(screenIndexToDuplicate).clone()
loopDiv.prepend(screenToPrepend)
if(loopDiv.children().length > 6) {
loopDiv.children().eq(loopDiv.children().length - 1).remove()
}
}
if(jQDocument.scrollTop() + jQWindow.outerHeight() > jQBody.outerHeight() - 200) {
//Duplicate elements on bottom while scrolling down
let bottomScreen = detectBottomScreen()
let indexBottomScreen = getIndex(bottomScreen)
let screenIndexToDuplicate
if(indexBottomScreen < maxIndex) {
screenIndexToDuplicate = indexBottomScreen + 1
} else {
screenIndexToDuplicate = 0
}
let screenToAppend = originalLoopDiv.children().eq(screenIndexToDuplicate).clone()
loopDiv.append(screenToAppend)
if(loopDiv.children().length > 6) {
loopDiv.children().eq(0).remove()
}
}
})

Related

JavaScript: Infinite scroll near bottom in div (70% near bottom)

I want to implement an infinite scroll inside a div whereby data is fetched when a user scrolls past 70% of the content.
Here is my current code:
element.onscroll = () => {
let dom = document.getElementById('scrollable');
let scrollY = dom.scrollHeight - dom.scrollTop;
let height = dom.offsetHeight;
let offset = height - scrollY;
if (offset == 0 || offset == 1) {
getMoreData()
}
};
Is there a way I can check whether the scroll is over 70%? Without executing getMoreData() multiple time?
I need to make sure that getMoreData function runs only once when scrolling down.
Implementations in Vue are also welcome.

How to craft an infinite scroller with IntersectionObserver so it doesn't bottom out?

I'm trying to build a simple pure Javascript infinite scroller using IntersectionObserver. I have it partially working, in the sense that when you scroll to the end, more items load. And the "infinite" effect works if you scroll slowly. But when you quickly scroll to the bottom (especially over and over), it bottoms out, ruining the "infinite" effect. (The code works better in Chrome---though eventually bottoms out---while Firefox bottoms out very quickly). I've tried various techniques, including placing my trigger element above the bottom of the list (e.g. before the last five items so that it triggers early), but that doesn't work all the time. It's almost like I need a negative threshold option, but that's not part of the spec for IntersectionObserver.
Any suggestions for how to make this code's scrolling effect appear infinite, especially in Firefox?
Here's my HTML:
<div id="items"></div>
<div id="trigger"></div>
And here's the Javascript:
(function () {
const items = document.querySelector("#items");
const trigger = document.querySelector("#trigger");
const options = { root: null, rootMargin: "0px", threshold: 0.0 };
const observer = new IntersectionObserver((entries) => {
entries.forEach((entry) => {
if (entry.intersectionRatio > 0) {
getMoreItems(15);
items.appendChild(trigger);
getMoreItems(5);
}
});
}, options);
observer.observe(trigger);
let itemcount = 0;
getMoreItems(15);
items.appendChild(trigger);
getMoreItems(5);
function getMoreItems(n) {
for (let i = itemcount; i < itemcount + n; i++) {
let item = document.createElement("p");
item.innerHTML = "this is item #" + i;
items.appendChild(item);
}
itemcount += n;
}
})();
Finally, here's a CodePen demo.
Is it a true infinite data set, or can you estimate the total number of items? If you know the total number of records in your data set, you could render empty rows/divs as placeholder that would expand the page to the approximate total scroll height, and lazy-load results as the divs come into the picture, as detected by IntersectionObserver.

Get scroll value on element with position:fixed

I have a page with a header section. In it, two blocks that move sideways after scrolling or dragging on the mobile.
I am trying to set the scrolling for the header, but I want too that the rest of the page stays in place until the side blocks reach left: -50% and right:-50%.
I have an event scroll set to header, with pageYoffset values.
I tried to set the rest of the content the page gives to the section with the position:fixed, but then the scroll does not work anymore, and do not count pageYoffset.
Do you have any ideas how to get around it, so that the rest of the page would scroll only after the full unveiling of the header?
(in short, the pink section should be on top and wait until the header disappears)
let current = $(window).scrollTop();
let windowHeight = $(window).height();
let eleLeft = $(".cd-half-left");
let eleRight = $(".cd-half-right");
let currPositionLeft = eleLeft.position().left;
let currPositionRight = eleRight.position().right;
let headerHeaight = $(".cd-section").height();
let halfBlockWidth = $(".cd-half-block").width();
let windowWidth = $(window).width();
$(window).scroll(function (event) {
current = $(window).scrollTop();
console.log({total:total,current:current});
var newPosition = ((current / headerHeaight)*100) / 2;
console.log(newPosition);
eleLeft.css({left:"-"+newPosition+'%'});
eleRight.css({right:"-"+newPosition+'%'});
});
FIDDLE
A solution would be not to use window scroll but instead handle scroll gesture (from mousewheel and touchmove) to control left and right panel, and prevent actual scroll when the panels are not fully opened.
so instead of $(window].scroll(handler), try with $('.cd-block').bind('mousewheel', handler) and $('.cd-block').bind('mousewheel', handler)
The handler being:
function updateCurrent(event) {
if (current >= 50) {
current = 50;
} else {
if (current <= 0) {
current = 0;
}
// if below 50 we cancel the event to prevent the scroll
event.originalEvent.preventDefault();
}
eleLeft.css({left:"-"+current+'%'});
eleRight.css({right:"-"+current+'%'});
}
Here is a buggy but working solution (keyboard space, up and down should be handled too):
fiddle

scroll to a div when scrolling, and scroll to top when div disappear

I have 2 divs on my webpage. first div is "#pattern" (red one), and second on is "#projets".(blue one)
when use scrolls for the first time, the window scrolls automaticaly to the the second div "#projets". I'm using jquery scroll-To plugin.
it works nice, even if when the users scroll with a large amount of scroll there could be on offset from the "#projets" div... If someone has an idea to correct this would be nice, but that's not my main trouble...
Now i'm trying to scroll back to the top of the page ("#pattern" div) as soon as "#pattern" div reappears when scrolling, the red one. so basically it should be as soon as the offset from the top of my screen of my div "#projets" is supperior to 1.
I've tried so many solutions without results, using flags, multiple conditions... it can be the same kind of thing as on this page, but user should be abble to scroll freely inside the page, not scrolling from hash to hash :
http://www.thepetedesign.com/demos/onepage_scroll_demo.html
here is my html :
<div id="pattern"></div>
<div id="projets"></div>
my css :
#pattern {
height:300px;
width: 100%;
background-color:red
}
#projets {
height:800px;
width: 100%;
background-color:blue
}
and my jquery :
var flag=0 ;
$(window).on('scroll',function(){
var top_projets_position = $("#projets").offset().top - $(window).scrollTop();
if((flag==0) && $(window).scrollTop()>1){
$(window).scrollTo('#projets', 500);
flag=1;
}
if($(window).scrollTop()==0){
flag=0;
}
});
here is jsfiddle :
http://jsfiddle.net/jdf9q0sv/
hope someone can help me with this, I can't figure out what I'm doing wrong, maybe a wrong method ! thanks
It looks like you need to track 3 things:
The scroll direction occurs.
The area you are currently viewing.
If scroll animation is currently happening (we need to wait until it's done, or problems will occur).
http://jsfiddle.net/vx69t5Lt/
var prev_scroll = 0; // <-- to determine direction of scrolling
var current_view ="#pattern"; // <-- to determine what element we are viewing
var allowed = true; // <-- to prevent scrolling confusion during animation
var top_projets_position = $("#projets").offset().top + 1;
$(window).on('scroll',function(){
var current_scroll = $(window).scrollTop();
if(current_scroll < top_projets_position && current_view=="#projets" && current_scroll < prev_scroll){
scrollToTarget("#pattern");
}
if($(window).height() + current_scroll > top_projets_position && current_view=="#pattern" && current_scroll > prev_scroll){
scrollToTarget("#projets");
}
prev_scroll = current_scroll;
});
function scrollToTarget(selector){
if(allowed){
allowed = false;
$(window).scrollTo(selector, {
'duration':500,
'onAfter': function(){ allowed = true; current_view = selector;}
});
}
}
This is just a quick solution based on your original code. A better solution would be to do something more Object Oriented (OOP) and track values in an object. Perhaps take an array of elements on object creation, grab all the boundaries and use the boundaries in your scroll handler to determine when to scroll to the next div.

Flickering Sidebar on Scroll

I have a sidebar that continually checks the users scrollposition and depending on their position, changes the background image of a specific image on a sidebar when needed to indicate which section on the page is being viewed. When viewing this sidebar locally, I see the sidebar flicker.
After uploading it to my site and viewing it there, the flickering stopped, but just in case, I wanted to know if anyone knows why and how to stop it. My website where the sidebar can be viewed in action (it's the sidebar on the left with number 1,2,3, and 4) is here. My code is below.
$(document).scroll(function() {
var greenheight = document.getElementById('welcome_logo').offsetHeight;
var redheight = document.getElementById('slideins').offsetHeight;
var blueheight = document.getElementById('section_overview').offsetHeight;
var yellowheight = document.getElementById('howsiteworks').offsetHeight;
if($(window).scrollTop() > redheight){
if (navslide != 2) {
if($(window).scrollTop() < greenheight+redheight){
$('#side2').css("background-image", "url(images/sidebar/side2_over.fw.png)");
$('#side1').css("background-image", "url(images/sidebar/side1.fw.png)");
$('#side3').css("background-image", "url(images/sidebar/side3.fw.png)");
$('#side4').css("background-image", "url(images/sidebar/side4.fw.png)");
var navslide = 2
}
}
}
if($(window).scrollTop() < redheight)
if (navslide != 1) {
{
$('#side1').css("background-image", "url(images/sidebar/side1_over.fw.png)");
$('#side2').css("background-image", "url(images/sidebar/side2.fw.png)");
$('#side3').css("background-image", "url(images/sidebar/side3.fw.png)");
$('#side4').css("background-image", "url(images/sidebar/side4.fw.png)");
var navslide = 1
}
}
if($(window).scrollTop() > redheight+greenheight){
if (navslide!=3) {
if($(window).scrollTop() < greenheight+redheight+blueheight){
$('#side3').css("background-image", "url(images/sidebar/side3_over.fw.png)");
$('#side1').css("background-image", "url(images/sidebar/side1.fw.png)");
$('#side2').css("background-image", "url(images/sidebar/side2.fw.png)");
$('#side4').css("background-image", "url(images/sidebar/side4.fw.png)");
var navslide = 3
}
}
}
if($(window).scrollTop() > redheight+greenheight+blueheight){
if (navslide!=4) {
if($(window).scrollTop() < greenheight+redheight+blueheight+yellowheight){
$('#side4').css("background-image", "url(images/sidebar/side4_over.fw.png)");
$('#side1').css("background-image", "url(images/sidebar/side1.fw.png)");
$('#side2').css("background-image", "url(images/sidebar/side2.fw.png)");
$('#side3').css("background-image", "url(images/sidebar/side3.fw.png)");
var navslide = 4
}
}
}
});
It's because you're using different images for every possible scenario (e.g. 1, 2, 3, 4, 1-over, 2-over, 3-over, 4-over, etc). The over images aren't loaded in the browser when scrolling. In other words, as you'r scrolling, your CSS goes, "I need to switch images. Let me remove the current image first... [image disappears] OK... now let me download this other image. Aaaaaaand, done! [image reappears]" This is the "blinking" that you're seeing.
Two basic techniques you can apply to mitigate this are:
Pre-loading the relevant images:
http://perishablepress.com/3-ways-preload-images-css-javascript-ajax/
http://css-tricks.com/snippets/jquery/image-preloader/
Use sprites (a single image instead of 8)
http://css-tricks.com/css-sprites/
http://www.smashingmagazine.com/2009/04/27/the-mystery-of-css-sprites-techniques-tools-and-tutorials/
Hope this helps.

Categories

Resources