Check whether an element is fully visible and then stop scrolling - javascript

I´m using FullSlider.js to create a full-slide-webpage. In case the red element is fully visible, I need the browser to block the scroll event (means: window is not moving, but I´m able to receive the action) and than after I did some stuff I want to enable scrolling again.
That is what I did so far:
I read a lot of stuff about this and tried even more solutions like:
stop scrolling:
1. stop scrolling of webpage with jquery does not work at all
How to programmatically disable page scrolling with jQuery does stop the scrolling, but it is not possible to enable scrolling again
event prevent default, works fine in chrome, but less fine in firefox
check if element is visible:
Check if element is visible after scrolling
I used the solution above and tried:
to check if the red element is visible (did not work)
checked if a tiny span above the red element is visible (did not work well)
checked if a tiny span below the red element is visible (did not work well)
checked if a tiny span above and below the element is visible (did not work at all)
tried some idea about getting the scrollTop of the red element and check if the bodys scrollTop is equal or near
In fact the 2. solution did work quiet well, but I just was not able to figure out the offset I needed to at to compensate the "fixed-header navigation".
Currently I´m using the "isScrolledIntoView" to detect whether the position fits (works well on large screens, does not work at all on small screens). For the stop scrolling, I´m using the following hack:
CSS:
.scrollHack { position: static; overflow: hidden; }
JS:
$(document).on('mousewheel', function(event, delta) {
// stopScroll and isStopped are booleans delivered by another script
if(isScrolledIntoView($("#s3")))
{
isStopped = false;
if(delta >= 0) {
$('#s3').get(0).contentWindow.car.next(); // car.next();
}
else{
$('#s3').get(0).contentWindow.car.previous();
}
stopScroll = $('#s3').get(0).contentWindow.isStopped;
}
if(!stopScroll && isScrolledIntoView($("#s3")))
{
event.preventDefault();
$("body").addClass("scrollHack");
}
else
{
$("body").removeClass("scrollHack");
}
});
function isScrolledIntoView(elem)
{
var docViewTop = $(window).scrollTop();
var docViewBottom = docViewTop + $(window).height();
var elemTop = $(elem).offset().top;
var elemBottom = elemTop + $(elem).height();
return ((elemBottom <= docViewBottom) && (elemTop >= docViewTop));
}
Was someone faced with an familiar situation and has some scripts or hacks that would help me out?

Sorry, I can't answer in a comment yet. So this is only a partial answer, regarding the second part of your question.
For checking whether your element is fully in view:
Try using jQuery innerHeight() instead of height(). This gives you the element height without margins and borders.
Checking for a tiny span above the red element should not be necessary. Wouldn't that be equal to just checking whether the top of the red element is on the screen? You could do that like this:
function isScrolledIntoView(elem) {
var docViewTop = $(window).scrollTop();
var elemTop = $(elem).offset().top;
return (elemTop >= docViewTop));
}
But this is only checking whether the top of your element is visible!
You say that your current solution does not work well on small screens. Could it be that the element you are checking is taller than the viewport on small screens?
Maybe this helps a little. Else it would be really good to see an example page or a jsfiddle example.

Related

Overflow hides content (should appear while scroll)

I am working on a website which uses snap.js and chart.js.
DEMO JSFIDDLE
After adding JavaScript to display the content from chart.js while user scroll, seems like it is in some trouble with the following style:
Line 10 - CSS: overflow: auto;
If I delete this style it works perfectly:
DEMO2 JSFIDDLE (without overflow)
The issue is that your window is no longer scrolling. Instead your .snap-content is. So you'll need to change the scroll handler to that element. You will then also have to modify your calculation a bit to work with this new setup:
http://jsfiddle.net/MU9aw/27/
function isScrolledIntoView(elem) {
var docViewTop = 0;
var docViewBottom = $(".snap-content").height();
var elemTop = $(elem).offset().top;
var elemBottom = elemTop + $(elem).height();
return ((elemTop <= docViewBottom) && (elemBottom >= docViewTop));
}
$(".snap-content").scroll(function () {
/* ... */
Note that your calculations will get considerably more complicated if your scrolling box does not fill the entire screen as you will need to determine if the element is visible within its box as well as that portion of the box being visible on the screen.
It's not the overflow that makes the issue.. It's the
.snap-content {
position: absolute; }
makes the issue. When I removed it, it works!
The problem is
$(window).scroll(function() {});
Doesn't fire when I scrolled maybe because since the element is absolute it keeps the original position in the screen without changing it. Make it to relative, and it will work.

Flickering with jQuery animate scrollTop

My problem
I am making a vertical website for a client who wishes to have the window "snap" to the nearest page when most of the element is visible in the viewport. So, if the page is 85% visible, it should scroll to be 100% visible.
My problem is that occasionally when scrolling all the way to the top or bottom of the viewport, the viewport will "stick" to the first or last element, preventing a few scroll events and causing a highly noticeable flicker.
A working fiddle is here: http://jsfiddle.net/RTzu8/1/
To reproduce the error, use the scrollbar to scroll to the bottom of the page. Then, scroll up with your mousewheel. You should see the flicker. Sometimes it takes a few refreshes or attempts, but the issue is highly reproducible.
I'm at a loss as to what could be causing this issue. See below for a run-down of my code and what I have tried to prevent it so far.
My code
To accomplish my snapping, I needed to detect whether an element was a certain percentage visible. So, I added a jQuery function, isNearScreen, below. I have thoroughly tested this function, and as far as I can tell it returns accurate results.
//Modification of http://upshots.org/javascript/jquery-test-if-element-is-in-viewport-visible-on-screen
//Returns "true" if element is percent visible within the viewport
$.fn.isNearScreen = function(percent){
var offset = 1 - percent;
var win = $(window);
var viewport = {
top : win.scrollTop()
};
viewport.bottom = viewport.top + win.height();
var bounds = this.offset();
bounds.bottom = bounds.top + this.outerHeight();
bounds.top = bounds.top;
//If the element is visible
if(!(viewport.bottom < bounds.top || viewport.top > bounds.bottom)){
//Get the percentage of the element that's visible
var percentage = (viewport.bottom - bounds.top) / this.height();
//If it's greater than percent, but less than 1 + (1 - percent), return true;
return (percentage > (1 - offset) && percentage < (1 + offset));
}
return false;
};
I then created a snap function, which makes use of Underscore.js's _.debounce function, to only fire on the trailing end of continuous scroll events. It fires after a 500ms timeout, and I am fairly (though not 100%) convinced that it is firing correctly. I have not been able to reproduce console logs that would indicate multiple concurrent firings.
//Snaps the screen to a page after scroll input has stopped arriving.
var snap = _.debounce(function(event){
//Check each page view
$.each($('.page-contents'), function(index, element){
//If the page view is 70% of the screen and we are allowed to snap, snap into view
if($(element).isNearScreen(0.7)){
$('html,body').animate({
scrollTop: $(element).offset().top
}, 300);
}
});
}, 500);
Finally, I bind to the window's scroll event
$(window).on('scroll', snap});
The (extremely simplified) HTML:
<div class="page">
<div class="page-contents"></div>
</div>
<div class="page">
<div class="page-contents"></div>
</div>
<div class="page">
<div class="page-contents"></div>
</div>
<div class="page">
<div class="page-contents"></div>
</div>
and CSS:
.page{
height: 750px;
width: 100%;
margin: 10px 0;
background: gray;
}
.page-contents{
height: 100%;
width: 100%;
}
What I've tried
I have tried the following, with no success:
Setting a boolean, 'preventSnap', on the window, checking its state, and only firing the animate portion of snap if it is set to false. After animation, set it to true, then set it to false after 500ms (which should in theory prevent double firings).
Calling .stop() on the element before running the snap animation.
Calling event.preventDefault() on the scroll event before running the animation.
Reducing and increasing my _.debounce delay. Interestingly, a lower _.debounce delay (200-300ms) seems to aggravate the problem and a higher _.debounce delay (1000ms) seems to fix it. This is not an acceptable solution, however, as it feels "long" waiting 1sec for the page to "snap".
Changing the heights of the elements
If there is any other information I can provide, please let me know. I'm at a loss!
I think this is a combination of events and how _.debounce works. I noticed in the fiddle (in Chrome) that the elements were 'jitterring' long after the snap finished. If you put a console log in the snap event handler you can see it's constantly being called after a snap even with no scroll inputs.
This must be the scroll animation itself setting off the snap, I tried to set a flag to prevent dual snapping and clearing the flag after the animation was finished -- however that didn't work I think because _.debounce is queuing the event to happen later (after the animation finishes and clears the flag).
So what does work is to add this as the start of the snap handler:
var nosnap = false;
var snap = _.debounce(function(event){
// Don't snap if already animating ...
if (nosnap) { nosnap = false; return; }
nosnap = true;
Fiddle
That prevents the animation directly firing the next snap event -- however that's going to cause issues if you scroll again during the animation.
So, that's a bit of a hack. Ideally you want to be able to tell what's causing the scroll event and react accordingly but there's no easy way to do that.
I absolutely think you need to stop the animation when handling a second scroll event as well.

Fly-in Fly-out effect on scroll jquery css animation

I am trying to make the elements on my site fly-in and fly-out on scroll.
This is the effect I am looking for.
http://nizoapp.com/
The effect in the nizo site is done with jquery, I think
I have tried many different ways to get this effect working, with Skrollr, scrollorama, and jquery animate and with css transitions etc etc etc
I decided to use css transitions as mad by the "css animation cheat sheet" (google it)
After a lot of effort and some borrowed code, I have got it half working, as in, I can get the elements to fly-in on down scroll, but not to fly back out on up scroll.
This is a jsfiddle with it half working
http://jsfiddle.net/mrcharis/Hjx3Z/4/
The code is......
function isScrolledIntoView(elem) {
var docViewTop = $(window).scrollTop();
var docViewBottom = docViewTop + $(window).height();
var elemTop = $(elem).offset().top;
return ((elemTop <= docViewBottom) && (elemTop >= docViewTop));
}
$(window).scroll(function () {
$('.box').each(function (i) {
if (isScrolledIntoView(this)) {
$(this).addClass("slideRight");
}
});
});
// this is the function to check if is scroll down or up, but I cannot get it to trigger the fly in effect,
(function () {
var previousScroll = 0;
$(window).scroll(function () {
var currentScroll = $(this).scrollTop();
if (currentScroll > previousScroll){
// i figure to put the fly-in code here
}
else {
// and the fly-out code here
}
previousScroll = currentScroll;
});
}());
I have tried using another function (code chunk) to check if the scrolling is down or up, but i can't get it working with the existing code.
Any help to get this working would be awesome
Have a nice day
I will post the solution one day, if I can figure it out, sure someone else would like to know
The trick to knowing whether you're scrolling up or down is not to ask. Make it relational by using the top offset of the elements in question. Then it's as easy as > or <, for the most part.
Though if you do want to get the current direction you could always record the last scroll position and compare it with the current one.
var before = 0;
$(window).scroll(function(event){
var now = $(this).scrollTop();
if (now > before){
//on down code
} else {
//on up code
}
before = now;
});
Like the answer here suggests.
I like to trigger the events based on the screen size and the element position in the screen, so it doesn't matter whether it's up or down, it follows the same rules forwards and backwards. That way instead of asking up or down, it just asks if it's scrolling and executes it accordingly.
If you need me to make changes to my fiddle for you, just let me know what you want to happen. I only made the fiddle because of the horrible job they did on the tympanus.net example. You don't make a tutorial to accomplish a simple task 2 pages of js, that's unnecessary and it doesn't provide any instruction other than "hey, you want to do this? Then copy and paste these things I put together that have no clear course of action, and way too much code to digest quickly". Which doesn't help anyone learn.
After some code borrowing from tympanus.net and using the modernizer library I came up with this.
I tried different approaches as well but all of them turned out to have some flaws in them so I find best approach to be using the sample code and the already provided modernizer JS library.

Detect Fixed position JavaScript not working in IE

i use YS for fixed position menu, is working fine in firefox but not working in IE.
$(function(){ // this is the shorthand for document.ready
$(document).scroll(function(){ // this is the scroll event for the document
scrolltop = $(document).scrollTop(); // by this we get the value of the scrolltop ie how much scroll has been don by user
if(parseInt(scrolltop) >= 80) // check if the scroll value is equal to the top of navigation
{
$("#navbar").css({"position":"fixed","top":"0"}); // is yes then make the position fixed to top 0
}
else
{
$("#navbar").css({"position":"absolute","top":"80px"}); // if no then make the position to absolute and set it to 80
}
}
}
Any solution fixing this problem for ie?
The problem, to me seems to be that IE doesn't trigger the .scroll event. At least, not in jsfiddle. If you explicitly trigger the event, that does seem to fix things. this fiddle was tested in IE8 and it works. The code:
$(function()
{
$(document).scroll(function()
{//add var here, avoid evil globals:
var scrolltop = $(document).scrollTop();
if(parseInt(scrolltop) >= 80)
{
$("#navbar").css({"position":"fixed","top":"0"});
}
else
{
$("#navbar").css({"position":"absolute","top":"80px"});
}
});//close properly
$(document).scroll();//explicit call
});//close this, too
You are missing ')' in your code working jsfiddle (tested in IE7 and IE9)
$(function(){ // this is the shorthand for document.ready
$(window).scroll(function(){ // this is the scroll event for the document
scrolltop = $(window).scrollTop(); // by this we get the value of the scrolltop ie how much scroll has been don by user
if(parseInt(scrolltop) >= 80) // check if the scroll value is equal to the top of navigation
{
$("#navbar").css({"position":"fixed","top":"0"}); // is yes then make the position fixed to top 0
}
else
{
$("#navbar").css({"position":"absolute","top":"80px"}); // if no then make the position to absolute and set it to 80
}
}); //here
});//here
For position fix must your parent element has this style
position:relative;
best regards

change div based on how far down the page you have scrolled

I am trying to change the text inside a div based on how far down a page you have scrolled. I've been tinkering with jQuery's scrollTop and document height but have so far failed to produce the desired results.
How would I get the position of an element on the page and then get jQuery to do something once you have scrolled to that elements position?
Help is much appreciated!
There was a question on Stackoverflow that asked something similar and I whipped up a small example to illustrate how to accomplish this. I can't find the question right now, but here is the example. In this example there is a div that is shown until you scroll to a certain element in the page at which point the div is hidden. You can change this to achieve what you want, as the idea is the same. Here is the code modified for what you need:
$(document).ready(function() {
function isScrolledIntoView(elem) {
var docViewTop = $(window).scrollTop();
var docViewBottom = docViewTop + $(window).height();
var elemTop = $(elem).offset().top;
var elemBottom = elemTop + $(elem).height();
return ((elemBottom >= docViewTop) && (elemTop <= docViewBottom));
}
var myelement = $('#formcontainer'); // the element to act on if viewable
$(window).scroll(function() {
if(isScrolledIntoView(myelement)) {
// do something when element is scrolled to and viewable
} else {
// do something when element is not viewable
}
});
});
Good old ppk from quirksmode.org can show you how to find the position of an element: "This script finds the real position, so if you resize the page and run the script again, it points to the correct new position of the element."

Categories

Resources