I see a difference between FF and Chrome (Version 22.0.1229.94 m) in this matter. FF is right (I would say).
when scrolling down a page and hitting then refreshing it, the callback of
$(window).ready(function(){
console.log( $(document).scrollTop() );
});
The console should say the amount scrolled after the window was ready, but in Chrome it's always 0
How can I show the get the amount of scrollTop in Chrome?
like some said in the comments, Chrome load the page, and then scroll it down.
Therefor when jQuery event is fired, the scroll is at 0.
You can do some work around like that :
$(document).ready(function() {
function getScroll() {
var scroll = $(window).scrollTop();
...
}
getScroll();
$(window).scroll(getScroll);
});
So in Chrome $(window).scroll(); will be fired just after the page is loaded.
EDIT: tested there http://fiddle.jshell.net/azaret/Mt65R/show/light/
Problem is that document.ready() in Chrome is executed before the browser scrolls down to the previous point and that is why you always get a zero value. A solution is provided here: Get vertical position of scrollbar for a webpage on pageload when the url contains an anchor
Related
My JS needs to know how far the user is scrolled down the page.
If I run this code:
document.addEventListener('scroll', event => console.log(document.pageYOffset));
...or do the same thing with scrollY ... or scrollTop ... or swap 'document' in for 'window' ... the console hears the event as I scroll, but always logs 'undefined'. This happens across multiple HTML documents, in Chrome and Firefox, whether I have any CSS reset on or not. What am I doing wrong?
It's window.pageYOffset not document.pageYOffset. Refer What is the difference between window, screen, and document in JavaScript?
I have ran into an issue that is plagued all over google but none of the provided solutions work correctly. I assume the majority of these solutions do not account for cross domain.
I have a website which I would like to instruct users to embed into their site with a (full page) IFrame. The problem is on some versions of Safari only. Elements within the IFrame can not scroll themselves into view.
I notice that if I do a same domain test the IFrame can scroll itself using window.parent.scrollTo(0,element.top). This works, but not cross domain. Another odd thing is that no other browser requires the window.parent method to scroll the IFrame, only Safari. All other browsers can use element.scrollIntoView() from within the IFrame. Note that I already use the JavaScript workaround to please Safari with cross-protocol IFrames.
Another issue I've only seen on Safari Mobile inside IFrame is that Bootstrap Modals appear out of view at the top of the IFrame when scrolled down. Although, I'm sure if we can correctly set the scroll position we should be able to set the modal position as well.
Here's what I've tried;
1. window.frames['IFrameName'].document.
getElementById("elmId").scrollIntoView();
Offset trick
Velocity.js
My last resort here (I think) is to use postMessage from within my IFrame to notify the parent domain to set the scroll position of the frame.
It seems to me that this issue has been around for an awful long time. Is there a better approach than this?
This ended up being a lot more research than code. What was going on was - I had code that resized the IFrame based on the content.
In all other browsers this works fine and eliminates the scroll bars. Turns out that Safari automatically sizes the Iframe leaving scrolls of it's own. In my application there are zero static pages. This leaves me with the issue of not being able to use the scrolling=no fix described in the link.
After discovering exactly what was going on I took a different approach to fixing elm.scrollIntoView(). The code is more comments then anything but the important parts are;
Detecting when to apply the Iframe fix with RequiresIframeScrollFix
Using elm.getBoundingClientRect().top to get our scroll position from within the Iframe.
Communicating to the parent to scroll with window.parent.postMessage
Receiving the message in the parent with window.addEventListener('message',...)
Here's what it looks like.
Iframe Site
Our Iframe site currently scrolls it's elements into view like this elm.scrollIntoView(); We've changed that to the following.
if (RequiresIframeScrollFix())
window.parent.postMessage(elm.getBoundingClientRect().top, "*"); // Tell IFrame parent to do the scrolling. If this is not a test environment, replace "*" with the parent domain.
else
elm.scrollIntoView(); // If not scroll into view as usual.
Optional: fix for bootstrap modal positioning in IOS IFrames using elm.getBoundingClientRect().top.
$('#modalId').css('top', elm.getBoundingClientRect().top); // This fixes modal not in view on Safari Iframes.
RequiresIframeScrollFix() is mostly made up of some well document code laying around SO to determine if we're in an Iframe on the IPad or IPhone.
// Used to help identify problematic userAgents.
var debugNavigator = false;
// Detects an issue on mobile where the Parent is an iframe which cannot have it's scroll bars removed.
// Presumably not a bug as safari will autosize it's iframes: https://salomvary.com/iframe-resize-ios-safari.html
// Can use "scrolling=no" fix instead if the parent knows the initial size of your iframe.
function RequiresIframeScrollFix() {
try {
// Debug navigator Agent
if (debugNavigator)
alert(navigator.userAgent);
// We know this issue happens inside an IFrame on;
// Safari iPhone
// Safari iPad
// Safari Desktop Works fine.
// Check for safari
var is_safari = navigator.userAgent.indexOf("Safari") > -1;
// Chrome has Safari in the user agent so we need to filter (https://stackoverflow.com/a/7768006/1502448)
var is_chrome = navigator.userAgent.indexOf('Chrome') > -1;
if ((is_chrome) && (is_safari)) { is_safari = false; }
// If we need to narrow this down even further we can use a more robust browser detection (https://stackoverflow.com/questions/5916900)
// Problematic browsers can be adjusted here.
if (is_safari && inIframe() && (
navigator.userAgent.match(/iPad/i) ||
navigator.userAgent.match(/iPhone/i)
))
return true;
else
return false;
} catch (e) {
alert(e.message);
}
}
// (https://stackoverflow.com/questions/326069/)
function inIframe() {
try {
return window.self !== window.top;
} catch (e) {
return true;
}
}
Parent Site
Our parent site holds the IFrame that was automatically sized by Safari Mobile. Therefore the parent site now has scroll bars of it's own, and not the IFrame. We set our listener up inside the parent site to scroll itself when it receives a message from the IFramed site.
// Safari Mobile Iframe Cross Domain Scroll Fix.
window.onload = function () {
// Calback function to process our postMessages.
function receiveMessage(e) {
try {
// Set the scroll position from our postMessage data.
// Non-Test pages should uncomment the line below.
//if (e.origin.includes("your-iframe-domain.com"))
window.scrollTo(0, e.data);
}
catch (err) {
}
}
// Setup and event to receives messages form our iframe (or window)
window.addEventListener('message', receiveMessage);
}
Hopefully this helps someone else dissect Safari Iframe problems on mobile. Also, let me know if I've overlooked a better solution.
The other option is iframeResizer library. There are two methods you can use from within iframePage: scrollTo and scrollToOffset, which do pretty much the same what you've described - they communicate via messages. It solved this problem for us in Safari.
Inside the parent page, when setting up resizing for the iframe, you have to assign a callback function to its onScroll event:
iframeNode.iframeResize({
...,
onScroll: ({x,y}) => callback
}
And inside iframe page:
if('parentIFrame' in window){
window.parentIFrame.scrollTo(0, someNode.offsetTop);
}
I have already checked a few questions in SO and over the Internet about this issue.
My problem statement is following: I have a gaming site which refreshes based on user action, and when it refreshes I want the user to be scrolled to a location that was decided before reload based on user action.
How I do it is, before reloading the page I store the calculated offset to localStorage.
window.onbeforeunload = function(){
var scrollTo = calculateNextLoadPosition();
//below function validates & calls localStorage.setItem(name,value);
storeLocalData("scrollTo",scrollTo);
console.log("Stored scrollPosition "+ scrollTo);
};
When page refreshes, I read this localStorage value and scroll page to that offset.
$(function() {
//retrieve the stored scroll offset as an integer
var scrollTo = parseInt(getLocalData("scrollTo"));
$('html,body').scrollTop(scrollTo);
console.log("Scrolled to "+scrollTo);
//also tried..
//$(window).scrollTop(scrollTo);
//$(document).scrollTop(scrollTo);
}
When I reload browser with this script, the calculated offset is always correct, the value in browser localstorage is also correct when I examine it using developer tools. But the browser never scrolls to that location even though in console it writes that it has scrolled to that position. It just stays at the top.
Additional info:
I do not have overflow-x or overflow-y anywhere in the HTML
It works like aa charm in Firefox
It is driving me nuts and I am about to chew on my hat in frustration!
Any pointers on what is going wrong is greatly appreciated!
In Chrome Devtools, you can break javascript on changing a DOM element's attributes, or on subtree modifications of an element.
I'm working on some legacy code that has some javascript that scrolls to the top of the page under certain situations, and I want to find the JS that does this.
Is there a way, in Devtools, so break on scroll events?
It could be jQuery or Prototype.js or event base JS that does it, and I've searched the codebase for .scrollTop or .animate, and I've found plenty of those, but none that are causing my issue.
I have no additional idea about actually breaking than the ones presented.
But i suspect it is not scrolling that causes the issue, but a '#' in the html.
x
is a very common pattern. when you forget (or something prevents) the "return false", the # (empty anchor) will be navigated to, which causes a scroll to top.
Check if the url has a # at the end after clicking!
You can inject this line of JS using the console to trigger the debugger when the scroll position changes programatically.
window.__defineSetter__("pageYOffset", function(){
debugger;
});
Then, view the call stack to see what triggered it.
If you don't want to activate the debugger, you can print the stack trace istead with the following code:
window.__defineSetter__("pageYOffset", function(){
console.log(new Error().stack);
});
Another option is to replace the windows scroll, scrollTo and scrollBy method with your own.
window.__defineGetter__('scroll', function(){
console.log('window.scroll getter :' + new Error().stack);
return function(x,y){
debugger; //or print stack trace
oldScroll(x,y);
}
});
Repeat for scrollTo and scrollBy.
I'm having a rather frustrating time trying to force my page to scroll back to the top after submitting a form.
The code I'm trialling this with is simple:
$('body').prepend('Click here');
$('body').on("click", "#testing", function() {
window.top.$('body, html').animate({ scrollTop: 0 }, 0);
});
This works, as intended, on FireFox - but not Internet Explorer.
It's worth noting that I'm using the UWA widget format and my code is essentially embedded within two iframes. There is an iframe for the HTML template and iframe containing this widget. I have control over neither of these frames, nor can I give you the full code because it is literally thousands of lines of horribly-written, misaligned HTML and JavaScript.
Here are some facts that I've put together to see if anyone can spot the problem because I'm don't really know where to begin looking:
In FireFox, this code works fine - clicking the link instantly scrolls the whole page to the top
If I open the IE console the Page Default Standard is "Quirks Mode". Changing this to "IE9 Standards" fixes the problem, i.e. clicking the link scrolls the whole page back to the top
Changing window.top to window.parent works in neither browser
Changing window.top to window.parent.parent also works in FF but doesn't work in IE
Changing animate({ scrollTop: 0 }, 0); to scrollTop(0) works in FF but doesn't work in IE
If I run the following alerts in IE, bizarrely (to me), here is the output:
alert(typeof window.parent); // object
alert(typeof window.top); // object
alert(typeof window.parent.parent); // object
alert(typeof window.parent.$('html')); // object
alert(typeof window.parent.$('body')); // object
alert(window.parent.offset().top); // alert doesn't trigger, no further alerts run until this line is commented
alert(window.parent.parent.offset().top); // alert doesn't trigger, no further alerts run until this line is commented
alert(window.parent.$('html').offset().top); // 0
alert(window.parent.$('body').offset().top); // 0
alert(window.top.$('html').offset().top); // 0
alert(window.top.$('body').offset().top); // 0
In short, it looks like window.top is accessible and so is the $('html') element from there... so why can't I get my page to scroll unless I force standards mode in my browser?