Using window.onscroll event to detect page/frame scrolling - javascript

I want to postion a DIV inside a page such that it is visible to the user even if the user vertically scrolls the page.
The page has a heading at the top of the page which is 75 px tall. Now when the user is at the top of the page and has not scrolled vertically, the DIV must be postioned below the heading. However, once the user scrolls the page causing the heading to go out of sight, the same DIV must now be position at the top of the page (i.e. near the top edge of the browser viewport)
My big concern is the support for window.onscroll event on browsers. I checked QuirksMode for compatibility (http://www.quirksmode.org/dom/events/scroll.html). It seems to have decent compatibility on IE and Firefox. However the Safari and Chrome support seems a bit quirky. And both these browsers are part of my target browsers' list.
Can anybody tell me if the window.onscroll event is an effective way of detecting page/frame scrolls? Any other suggestions?
P.S. I have considered using the CSS position: fixed rule. It is close to the solution but the DIV is just stuck to one position and I cannot have it adaptively move based on the visiblity of the heading.
Thanks!

Here's another alternative method you could try. I use it to position a toolbar div on top of the page (works for ipad too).
Instead of using the onScroll event, I am using a timer to fire every 500ms to detect where the windows is scrolled to via scrollTop . You could adjust the timer to about 200ms if you like.
Here's a stripped down sample of my code:
This jquery code checks when and if my dom element div named "floatlayer" (which is a div that contains my buttons toolbar) is ready and then calls the function setRepeater
$(#floatlayer").ready(function () {
return setRepeater();
});
Then, this is the function that creates a timer to keep executing the function "keepIncrease" every 500ms
function setRepeater() {
aTimer = window.setInterval("keepIncrease()", 500);
return false;
}
This is the function keepIncrease() which is repeated every 500ms and is responsible to position the toolbar div based on the current window scrolled position :
function keepIncrease() {
var divToolbar = $("#floatlayer")[0];
var currentPos = $(window).scrollTop();
divToolbar.style.top = currentPos + "px";
return false;
}
Something else out of topic:
If your content is inside an iframe, you could also use $(window.parent).scrollTop() instead of $(window).scrollTop()

If you read about the clunkiness in WebKit on Quirksmode, you'll notice the following:
Safari (but not on iPhone) and Chrome seem to monitor scrollTop acces in order to determine whether the user has scrolled an element. The log function of my test script changes scrollTop regularly, and Safari responds by firing a scroll event. Since the logging of this event changes the log element's scrollTop once more, scroll events will be fired continuously.
All this happens when the log element at the bottom of the page doesn't have a scrollbar yet, when it has a normal overflow: visible, and even when I set scrollTop to 0 each time a new event is logged. The buggy behaviour stops only when I remove the scrollTop line entirely.
This issue shouldn't affect what you're trying to achieve since you're not setting the scrollTop of any element. You're attaching onscroll to the window, which appears to have no issues between any browser anyway.

Why not just use "fixed"?
Oh, I see, I missed the part about the header.
You could still utilize the position:fixed option, though. You would just set the position against "body" initially (accounting for the 75px gap), and once the header leaves viewability, you can realign the div against the top of the viewport. But without using onscroll in some way or another you probably won't be able to do what you want to do. Sometimes you just have to make the decision: Do I want the feature more, or the people more?

Related

On scroll function it worked with $(window) but not with $(document), why?

I am working on a function where I have to hide the sticky footer once it reach an element -> #line-before-related-article.
When I use $(document) the sticky footer disappears when I start scrolling down, which is not what I want.
When I use $(window) the sticky footer disappears before of reaching #line-before-related-article, which is almost what I need. I want the sticky footer disappearing ONLY when it reaches the div with the id #line-before-related-article
$(window).scroll(function() {
if ($(this).scrollTop() + $(this).height() >= $('#line-before-related-article').position().top) {
console.log(console.log($('#line-before-related-article').position().top))
$('.sticky-footer').hide();
}
});
I think my issue will be fix once my function works using $(document) properly.
Any suggestions?
The window object carries the scroll property and fires the corresponding event about the browser. As you see on its name, the document object refers to the DOM elements from the top to the bottom.
scrolling the content in the browser does not fire an event on a DOM object!
you have to enable the scrolling feature by playing with CSS
here is the explanation from jquery website:
https://api.jquery.com/scroll/
The scroll event is sent to an element when the user scrolls to a different place in the element. It applies to window objects, but also to scrollable frames and elements with the overflow CSS property set to scroll (or auto when the element's explicit height or width is less than the height or width of its contents).
when your element does not have scrolling feature, it will not carry the scroll event capability.
you have to take care of the CSS code to enable the scroll event.

How to eliminate bounce-on-scroll?

This page uses a bit of JS to prevent the top of the left-side panel from scrolling past the top boundary of the viewport.1
Under Chrome 31 and Firefox 25, the left-side panel remains rock-solid as one scrolls past the top of the containing div, but in other browsers (e.g. IE 11 and Safari 6) the left-side panel "bounces" vertically as one scrolls. (Once the scrolling stops, the position of the left-side panel stabilizes.)
Here's the JS/jQuery code responsible for this effect:
(function () {
var w = $(window),
lc = $('.left-panel');
w.scroll(function () {
var st = w.scrollTop(),
ot = lc.offset().top;
$('.vfloat').css('top', Math.max(0, st - ot));
});
}());
Question: How can I eliminate this unwanted "bouncing" of the left-side div?
EDIT: cleaned up and simplified the code snippet.
1To make this effect possible, you may need to resize your window's vertical dimension so that enough of the right-side panel falls outside the viewport.
It is the way each browser fires scroll event. You use height calculations which are very expensive and cause reflows of the webpage, and it depends on browser how it handles that.
I can suggest you 2 options that will solve your problem:
1) Simply use jQuery animate to change position of your left div, that way the position will change smoothly, you can use even very fast speeds. If you don't want to use jQuery you can simulate the same behavior by writing your own code and using timers to change top position smoothly or even css3 animations.
2) The second way (and I think this is the preferred way) is not to use javascript for position manipulation in this case and use javascript only to assign position: fixed class to your left container on some conditions. It will still cause reflows, but you won't have such delay caused by scroll event.
Solution 1 - using css3 transition and jQuery for smooth animation: http://jsfiddle.net/6bYhx/4/ (the same can be accomplished with jQuery.animate())
Solution 2 - using position: fixed and addClass (the problem with IE still persists as scroll event is delayed): http://jsfiddle.net/S5Sgu/
So I think that the optimal solution would be smooth animation (Technique 1) with some modifications.

Inability to scroll after turning div from absolute to fixed positioning using jquery

I have a div that gets a 'fixed' class added to it once the user scrolls past a certain point in the parent div. The fixed class simply changes the child div from absolute positioning to fixed positioning.
However, a problem occurs when the user scrolls to a certain point when the 'fixed' class is added (as specified by the 'begin variable' in the js). The user loses the ability to scroll up or down for a number of seconds. And to make matters more complicated, this problem only occurs on the first of six parent divs that uses this code.
Here's the jquery code that adds the 'fixed' class:
var begin = 164;
$("#portfolio_window").scroll(function () {
var y = $(this).scrollTop();
if (y >= begin) {
$('.details').addClass('fixed');
} else {
$('.details').removeClass('fixed');
}
});
If I change the 'begin' variable to something like 600, the user loses the ability to scroll around 600px from the top of the div.
You can try to reproduce the problem at http://dev.zachboth.com/
Here's the easiest way that I've been able to reproduce the problem:
Use Safari
Clicking 'Various Logos' in the 'Work' section
Scrolling down quickly once the 'Various Logos' section appears
It may take several attempts to actually have the problem occur
I can explain your problem:
The problem is that on the "page" you mention being broken has you scrolling in div#portfolio_window. The position:fixed element you mentioned is positioned relative to the window. When you scroll on that element, it's trying to scroll the window (not the parent div).
http://jsfiddle.net/NThY7/
The solution is a bit more involved. I'll hop back on later with a solution.

Detect when Browser Scrolls Below a Certain Point

I have a webpage filled with divs, and when the page reaches 300px from the bottom, it loads more divs.
I'm having trouble finding a detection that works everywhere.
I need some JavaScript (i.e. not JQuery) if statement to put into the body's onscroll function that will detect the browser scrolling below 300px from the bottom, which works with IE, FF, Chrome, Opera, Safari, Android browsers, iBrowsers, etc.
You could use a library like
http://code.google.com/p/jquery-appear/
And bind to the last element you dynamically display in each batch, so that when it comes into view, the next batch is shown.
I'm pretty sure you can use jQuery's "scrollTop" method on the document object or possibly the body tag.
i.e.
if ($(document).scrollTop() > whatever) {
doWhatever();
}
You have to know the position of the point, then checks the window scrollTop
if ($(window).scrollTop() > point) {
//Carry On
}

Event that gets fired before (not after!) DOM elements are scrolled in javascript

Basically, I would like to do some pre-processing before the DOM elements are scrolled. The problem is that the scroll event is fired AFTER the DOM elements are scrolled. I know that when you use the mousewheel to scroll, the mousewheel scroll event gets fired before DOM elements are scrolled although it does not provide you with the anticipated scroll position and it is only one type of scroll. I am wondering if there is any event that gets fired for every scroll method(eg. mousewheel, dragging the scroll bar, pushing the down arrow etc.) BEFORE the DOM elements are scrolled. It does not have to be an event. I am not trying to scroll to a certain position so scrollTo would not be applicable.
The chain of event with on scroll:
User scrolls -> DOM elements physically scroll -> fires onScroll event -> handle stuff
The desired chain of event:
User scrolls -> some event is captured and do what I want to do -> DOM elements physically scroll -> fires onScroll event -> handle stuff
Heres something you might want to try.
Give your page overflow:hidden so that no scroll bars appear, then place an absolutely positioned div with the correct width & height over the content. When this div is scrolled, you can then update any underlying content before re-triggering the event.
You would need to pass through clicks etc as well, so this is really a hack. Something like jQuery would help with the triggering of the events and measuring the height of the content.
EDIT: css pointer-events:none may help here depending on the browser. See https://developer.mozilla.org/en/css/pointer-events
The best you can do is when onScroll fires, if scrollTop > thingToStick's distance from the top, then set position: fixed on thingToStick otherwise, set position to whatever it was originally. It'll flicker when changing from not-sticking to sticking, but besides that, you won't get any flickering.
in sudo-ish code:
onScroll = function()
{
if(scrollTop > thingToStick.y)
thingToStick.position = "fixed";
else
thingToStick.position = "relative";
}
In browsers that don't support fixed positioning, you're stuck with the flicker...
Never tryed this before, but to break the chain of event it would be possible to :
Capture the scroll event
Do your stuff
Use preventDefault() and stopPropagation to inhibit the event
Fake a new scroll event using the original one (this should be feasible I think)
Hope this will help.

Categories

Resources