Detecting by how much user has scrolled - javascript

I have an image pop-up ability on my website, in order to show users the full resolution picture when they click on a smaller version on the page.
This is the current CSS that positions it:
div#enlargedImgWrapper {
position: absolute;
top: 30px;
left: 55px;
z-index: 999;
}
The problem now is that if I click on an image further down the page, the window still appears in the top left corner of the page, where I can't see it until I scroll back up. I need it to appear relative to the window, whatever its current position relative to the document is.
Note: I don't want to use position: fixed; as some images might be taller than the screen, so I want users to be able to scroll along the image as well.
My idea was to use JS to change the top value:
var scrollValue = ???;
document.getElementById('enlargedImgWrapper').style.top = scrollValue+30 + 'px';
How can I detect by how much the user has scrolled down the page (var scrollValue)?
Or is there a 'better' way to do this?
Edit: if possible I would like to do this without jQuery.

Pure JavaScript uses scrollTop and scrollLeft:
var scrollLeft = (window.pageXOffset !== undefined) ? window.pageXOffset : (document.documentElement || document.body.parentNode || document.body).scrollLeft;
var scrollTop = (window.pageYOffset !== undefined) ? window.pageYOffset : (document.documentElement || document.body.parentNode || document.body).scrollTop;
https://developer.mozilla.org/en-US/docs/Web/API/Element.scrollTop
jQuery version:
var scrollLeft = $(window).scrollLeft() ;
var scrollTop = $(window).scrollTop() ;
What you need is this:
document.getElementById('enlargedImgWrapper').style.top = (scrollTop+30) + 'px';

document.getElementById('enlargedImgWrapper').scrollTop;
MDN
This property's value equals the current vertical offset of the
content within the scrollable range. Although you can set this
property to any value, if you assign a value less than 0, the property
is set to 0. If you assign a value greater than the maximum value, the
property is set to the maximum value.
You can set this property inline, but the results might be
inconsistent while the document is loading.
scrollTop property

Related

Get Android Chrome Browser Address bar height in JS

How do I get the height of the address bar in JavaScript in the Chrome browser for Android (marked by red rectangle in left picture)? I need to know that as it disappears while scrolling down and I need to react to that because the viewport height is different then.
One solution I already figured out:
Get viewport height at initial state:
var height = Math.max(document.documentElement.clientHeight, window.innerHeight || 0);
Get viewport height when the address bar has disappeared
Compute difference between both values
Problem is that you have to be in the second state to know that.
Because 100vh will be larger than the visible height when the URL bar is shown. According to this.
You can calculate the height of the URL bar by creating a 0-width element with 100vh height.
<div id="control-height"></div>
#control-height {
height: 100vh;
width: 0;
position: absolute;
}
Then using javascript compare window.innerHeight with the height of this element.
const actualHeight = window.innerHeight;
const elementHeight = document.querySelector('#control-height').clientHeight;
const barHeight = elementHeight - actualHeight;
The thing you're are looking for is url bar resizing. Since Android's chrome v56, it's recommended by David Bokan to use vh unit on mobile. There is a demo in that article, clicks the link to get more informations and how to use it on mobile.
When the user is scrolling down the page, a window.resize event is throwed.
You could update your page by catching this event with an event listener.
More informations : mobile chrome fires resize event on scroll
Best approach for me was to have something like that:
$(document).ready(function(){
var viewportHeight = Math.max(document.documentElement.clientHeight, window.innerHeight || 0);
var viewportWidth = Math.max(document.documentElement.clientWidth, window.innerWidth || 0);
var isPortrait = viewportHeight > viewportWidth;
$( window ).resize(onresize);
function onresize() {
var newViewportHeight = Math.max(document.documentElement.clientHeight, window.innerHeight || 0);
var newViewportWidth = Math.max(document.documentElement.clientWidth, window.innerWidth || 0);
var hasOrientationChanged = (newViewportHeight > newViewportWidth) != isPortrait;
var addressbarHeight = 130;
if (!hasOrientationChanged && (newViewportHeight != viewportHeight)) {
addressbarHeight = Math.abs(newViewportHeight - viewportHeight);
if (newViewportHeight < viewportHeight) {
// Android Chrome address bar has appeared
} else {
// Android Chrome address bar has disappeared
}
} else if(hasOrientationChanged) {
// Orientation change
}
viewportHeight = newViewportHeight;
viewportWidth = newViewportWidth;
isPortrait = viewportHeight > viewportWidth;
}
});
Had the same issue today, turns out there is no easy way to figure out the height of the url bar directly. As far as I know, none of the directly accessible variables in javascript can tell you how much the size of "100vh" really is.
On mobile browsers, 100vh may or may not include the height of the url bar, which leaves us in a tricky situation, if we want to size a div to the exact height of the visible content area of the browser during load.
I figured out a workaround though that worked pretty neat for me, here's what I did:
add a dummy property on your html root element with a size of 100vh. In my case, i used the "perspective" attribute, which worked for me
then you can get the address bar size with the following code:
var addressBarSize = parseFloat(getComputedStyle(document.documentElement).perspective) - document.documentElement.clientHeight
I had a container with dynamic content that had to always have at least viewport's full height (and be scrollable if the content doesnt fit on the screen).
So if you need a fixed height, just replace "min-height" with "height" in my solution.
That's how I dealt with it.
// calculate min-height on init
$(".content-container").css("min-height", `${window.innerHeight}px`);
// recalculate the min-height everytime the bar appears or disappears
$(window).resize(() => {
$(".content-container").css("min-height", `${window.innerHeight}px`);
});
It works for android's address bar and also safari's bars (in safari mobile there can be top and the bottom bar aswell).
Then to make the transition smooth, you can apply a css rule:
.content-container{
transition: min-height 500ms ease;
}

JavaScript getBoundingClientRect() changes while scrolling

I want to have the exact distance between the Y-coordinate of an element an the Y-value=0, which I consider as the top of the document.
myElement.getBoundingClientRect().top;
But the value of getBoundingClientRect() seems to change while scrolling. How can I get the real distance between myElement and the Y-coordinate=0 (top of document)?
It is because getBoundingClientRect() gets values with respect to the window(only the current visible portion of the page), not the document(whole page).
Hence, it also takes scrolling into account when calculating its values
Basically, document = window + scroll
So, to get the distance between myElement and the Y-coordinate=0 (top of document), you would have add the value of vertical-scroll also:
myElement.getBoundingClientRect().top + window.scrollY;
Source: https://developer.mozilla.org/en-US/docs/Web/API/Element.getBoundingClientRect
getBoundingClientRect needs a bit more care to avoid bugs in scrollY/pageYOffset:
function absolutePosition(el) {
var
found,
left = 0,
top = 0,
width = 0,
height = 0,
offsetBase = absolutePosition.offsetBase;
if (!offsetBase && document.body) {
offsetBase = absolutePosition.offsetBase = document.createElement('div');
offsetBase.style.cssText = 'position:absolute;left:0;top:0';
document.body.appendChild(offsetBase);
}
if (el && el.ownerDocument === document && 'getBoundingClientRect' in el && offsetBase) {
var boundingRect = el.getBoundingClientRect();
var baseRect = offsetBase.getBoundingClientRect();
found = true;
left = boundingRect.left - baseRect.left;
top = boundingRect.top - baseRect.top;
width = boundingRect.right - boundingRect.left;
height = boundingRect.bottom - boundingRect.top;
}
return {
found: found,
left: left,
top: top,
width: width,
height: height,
right: left + width,
bottom: top + height
};
}
The bugs to avoid are:
scrolling in Android Chrome since Chrome Mobile 43 has wrong values for scrollY/pageYOffset (especially when the keyboard is showing and you scroll).
Pinch-zoom in Microsoft IE or Edge causes wrong values for scrollY/pageYOffset.
Some (obsolete) browsers don't have a height/width e.g. IE8
Edit: The above code can be simplified a lot by just using document.body.getBoundingClientRect() instead of adding a div - I haven't tried it though so I am leaving my answer as it stands. Also the body needs margin:0 (reset.css usually does this). This answer simplifies the code down a lot, while still avoiding the bugs in jQuery.offset()!
Edit 2: Chrome 61 introduced window.visualViewport to give correct values for the actual viewport which is probably another way to fix issues; but beware that Android Chrome 66 was still buggy if Settings -> Accessability -> Force enable zoom was ticked (bugs with orientation change, focused inputs, absolutely positioned popup wider than viewport).

Javascript: check IF page is at the top

Is there a way to check, with JavaScript, if the page is at scroll(0,0)?
Reason being I've got a full page slider that I need to pause the second the page is not at origin.
And it might not necessarily be because the page is being scrolled live as I've got internal HTML # links that would load the page right to a scrolled point without actually scrolling.
So the check needs to be is the page not at the top, as opposed to, has the page been scrolled.
Try this:
document.body.scrollTop === 0
You can check if window.scrollY (the number of pixels the window has scrolled vertically) is equal to 0. If you want to check if the window has been scrolled to its leftermost, you can check if window.scrollX (the number of pixels the window has scrolled horizontally) is equal to 0. If you combine the two, it will ensure the window is at (0,0) position.
if(window.scrollY==0){
//user scrolled to the top of the page
}
if(window.scrollX==0){
//user scrolled to the leftmost part of the page
}
if(window.scrollY==0&&window.scrollX==0){
//user scrolled to the leftmost part of the top of the page—i.e., they are at position (0, 0)
}
Demo:
var goToTop = document.querySelector('#backToTop');
goToTop.addEventListener("click", function(e){
window.scroll({top: 0, left: 0, behavior: 'smooth'});
//scroll smoothly back to the top of the page
});
window.addEventListener("scroll", function(){
if(window.scrollY==0){
//user is at the top of the page; no need to show the back to top button
goToTop.style.display = "";
} else {
goToTop.style.display = "block";
}
});
body,html{height:3000px;position:relative;margin:0}#footer{position:absolute;width:100%;bottom:0;left:0;right:0;background-color:#1e90ff;text-align:center}#backToTop{position:fixed;right:0;bottom:0;display:none;z-index:1}#header{position:absolute;width:100%;top:0;left:0;right:0;background-color:#1e90ff;text-align:center}
<div id="header">Header</div>
<button id="backToTop">Back To Top</button>
<div id="footer">Footer</div>
For better browser compatibility, use window.pageYOffset instead of window.scrollY and window.pageXOffset instead of window.scrollX.
The following code can be used in cases when full browser compatability is necessary (i.e., IE < 9):
var x = (window.pageXOffset !== undefined)
? window.pageXOffset
: (document.documentElement || document.body.parentNode || document.body).scrollLeft;
//number of pixels scrolled horizontally (work with this value instead of window.scrollX or window.pageXOffset)
var y = (window.pageYOffset !== undefined)
? window.pageYOffset
: (document.documentElement || document.body.parentNode || document.body).scrollTop;
//number of pixels scrolled vertically (work with this value instead of window.scrollY or window.pageYOffset)
Updated Answer for 2019
document.body.scrollTop is deprecated and doesn't work at all in Chrome anymore. The best way to solve this is simply looking at all three possibilities to have a cross browser solution.
!window.pageYOffset
One of these three should work on all browser types. If the value equals 0, your at the top of the viewport.
i think you can get the position using jQuery $(window).scrollTop()

Javascript to detect if item no longer visible due to scrolling

I've got a javascript slideshow at the top of my page. When a slide changes to the next image, I call another function to change the background colour of the page.
The client wants the background colour to stop changing when the slideshow is no longer in view, i.e. when the user has scrolled down the page.
Is there any way to detect if an element is no longer visible due to scrolling?
Test code in jQuery
function test() {
var $elem = $('.test');
var visibleAtTop = $elem.offset().top + $elem.height() >= $(window).scrollTop();
var visibleAtBottom = $elem.offset().top <= $(window).scrollTop() + $(window).height();
if (visibleAtTop && visibleAtBottom) {
alert('visible');
} else {
alert('invisible (at ' + (visibleAtTop ? 'bottom' : 'top') + ')');
}
}
Full working example at http://jsfiddle.net/9PaQc/1/ (Updated: http://jsfiddle.net/9PaQc/2/ )
P.S. This only checks for vertical scroll. For horizontal, just do the same with top replaced with left, Y -> X and height() -> width()
EDIT
Made it all the way jQuery (to ensure x-browser compatibility) by changing window.scrollY -> $(window).scrollTop()
You can use the jQuery $.scrollTop function, probably from a scroll event handler to script this.
Use the window.pageYOffset to determine scroll amount in window. Use current offset of the object to check if it is in view. Note that these values are mostly browser dependent, so first check if it exists then act on it.

How to find (in javascript) the current "scroll" offset in mobile safari / iphone

I'd like to know the x/y offset of the how far the user has "scrolled" within the viewport in mobile safari on the iphone.
Put another way, if I (through javascript) reloaded the current page, I'd like to find the values I'd need to pass into window.scrollTo(...) in order to reposition the document/viewport as it is currently.
window.pageXOffset always reports 0
jquery's $('body').scrollTop() always reports 0
events have a pageX, but this won't account for the scrolling of the page that happens after you release your finger if your gesture was to "flick" the page up/down. Namely, it'll give me a point when the finger leaves the screen, but that doesn't always match where the page will be after it's finished scrolling.
Any pointers?
window.pageYOffset should give you the current scroll offset. There's window.pageXOffset if you need it too.
I had the same problem... this did the trick:
var scrollX = window.pageXOffset; var scrollY = window.pageYOffset;
Got it from this question: Get current position of the viewport in Mobile (iPhone) Safari
This will indeed work:
var scrollX = window.pageXOffset;
var scrollY = window.pageYOffset;
If you are viewing content in an iFrame (which is common in WebViews for instance), then you will need to add parent:
var scrollX = parent.window.pageXOffset;
Also note that these values are not writeable. So to change the scroll position, you will need to use window.scrollTo method:
var scrollX = window.pageXOffset;
var scrollY = window.pageYOffset;
window.scrollTo(scrollX -100, scrollY -100);
Have you tried the pure js way?
document.body.scrollTop
Here is a simple code to find if the device is iphone and also to change the scroll position to specific position based on some action. I had an issue with iphone only when I click and open an image as a popup, because vertical scroll goes down than where I wanted to be. So I wrote this code and it solved the issue.
if((navigator.userAgent.match(/iPhone|iPad|iPod/i))){
('#tutorial-landlord').click(function(){
window.scroll(100, 1500); // x, y (horizontal, vertical position)
});
}
To find the scroll position. Just go to console in chrome and write
window.scrollY for vertical and see how the position changes so note that number and give it in place of x and y
I had the same issue on iPad. Just desactivate the console. The viewport height changes when the console is open in Safari.
If for whatever reason pageXOffset and pageYOffset fail, the solution is straightforward, but rather silly:
// force an element to top left of the page
var topLeftMarker = document.createElement("span");
topLeftMarker.style.position = "absolute";
topLeftMarker.style.left = "0";
topLeftMarker.style.top = "0";
document.body.appendChild(topLeftMarker)
function scrollOffset() {
// getBoundingClientRect() returns the rectangle of the element in viewport space,
// which *is* scrollLeft and scrollTop
const rect = topLeftMarker.getBoundingClientRect();
return { x: rect.left, y: rect.top }
}

Categories