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!
Related
The Problem
I have a function that should run on window.onbeforeunload. In Chrome, this works correctly and runs whenever a tab or window is closed or refreshed. In Firefox, however, it only runs on refresh, not close.
The Code
Here is an example:
var onStorageUpdate = function(){
var lastUnloaded = localStorage.getItem("LastUnloaded");
if(lastUnloaded === null){
$("div").text("Never stored");
}
else{
$("div").text(lastUnloaded);
}
};
onStorageUpdate();
window.addEventListener("beforeunload", function(){
var now = Date.now();
localStorage.setItem("LastUnloaded", now);
});
window.addEventListener("storage", function(){
onStorageUpdate();
});
Here is the order of events that should work in the above code:
On initial page load, attempt to get LastUnloaded from localStorage. If nothing is retrieved, show "Never Stored", otherwise show the value that was stored (should be a long integer timestamp)
Upon unloading a tab, updated LastUnloaded with the current timestamp. This is the part that doesn't seem to work in Firefox when closing a window.
Upon change in localStorage, update the DOM to show the timestamp
Demo
Here is a codepen of the example: http://codepen.io/jakelauer/full/NqRyqQ/
In order to test it, open the link in two different windows or tabs. You should notice that when you refresh either tab, both tabs update to show the same timestamp. In Chrome, you will notice that if you close one tab, the other tab will update its timestamp. In Firefox, you will notice that the timestamp does not get updated.
Any ideas? Thanks in advance!
I ended up just using onunload, which worked fine everywhere.
I'm working on a solution to detect exit intent on safari mobile. (or any mobile browser for that matter)
On desktop I can track curser movement and when the user breaks the plane of the webpage I can initiate a pop up. See http://www.quicksprout.com/about/ as an example. Move your curser up to the back button on the browser and as soon as your curser breaks the webpage a pop up will appear. How can I solve this in a mobile environment?
Is there any way to detect when someone clicks the Safari address bar and before the favorites screen appears I can launch a pop up then?
Thank you in advance for the help.
I know this is over a year later, but maybe my answer might still help someone in the future.
On some of my sites, I found that mobile exit intent often consists of a slight upward scroll before the user hits their back button. For example, users often scroll down the page quite a bit while consuming content, but when they're ready to leave they might scroll upwards slightly (say 5-10% of the page height), and then they'll go hit the back button or close the tab.
I use that knowledge to pop up a newsletter sign up form on some of my content sites, and it actually works well without annoying the user. So if I ever detect that a user scrolled down at least 50% of my page, then back up by at least 5%, I hit them with a popup since I think they liked my content but are ready to exit the page. I wrote some simple Javascript that actually lets me detect such behavior at https://github.com/shahzam/DialogTriggerJS
Not sure if that's the exact answer you're looking for, but hope that helps a bit!
I just came back from a long trip around the web with the same goal in mind however as of now - you really are not able to detect if a user clicks on the address.
However I found out that you can look for patterns that users are making before they are ready to leave your website or abandon shopping cart. Here is show how we solved this and made mobile exit intent work on all mobile devices in case if the user quickly scrolls back up the page since that can be a sign that shows that the user has lost interest in our content and might want to leave.
Detecting if the user is on a mobile device.
This part is rather simple - we use Javascript to check if the event is "touchstart" and if so, we are adding a class to our body tag:
jQuery(document).on('touchstart', function(){
$(body).addClass('on-mobile-device');
});
Detecting the scroll direction, scroll speed and displaying Exit Intent popup:
function myScrollSpeedFunction(){
if( jQuery('body').hasClass('on-mobile-device') ){
if(my_scroll() < -200){
//Your code here to display Exit Intent popup
console.log('Must show mobile Exit Intent popup')
}
}
}
var my_scroll = (function(){ //Function that checks the speed of scrolling
var last_position, new_position, timer, delta, delay = 50;
function clear() {
last_position = null;
delta = 0;
}
clear();
return function(){
new_position = window.scrollY;
if ( last_position != null ){
delta = new_position - last_position;
}
last_position = new_position;
clearTimeout(timer);
timer = setTimeout(clear, delay);
return delta;
};
})();
jQuery(document).on('scroll', myScrollSpeedFunction );
This is basically it. This way you are not interrupting the user's flow since the user has already finished looking at the content and going up very quickly and we can present him with a message.
What we have done ourselves besides this code is to make sure our Exit Intent popup is displayed only in case if the user has got a product in his shopping cart since we are suggesting to save the users shopping cart and remind about his abandoned cart via email.
You can test it out on our product page here: https://www.cartbounty.com, just remember to add a product to the shopping cart before you test drive it on your mobile device.
At least on mobile safari, you're looking for the window.onpagehide function. This event will fire immediately after the page is hidden.
Here is a snippet showing this code in action:
<!DOCTYPE html>
<html>
<head>
<script> window.onpagehide = function(e) { alert("Don't go! I'm lonely!"); }</script>
</head>
<body>
</body>
</html>
Unfortunately, it looks like if you want an event to fire before the page is hidden, you're out of luck, because mobile Safari halts execution of everything on the page when the user clicks on the address bar. This means that you cannot, for example, monitor the page height to see if the user is typing on the keyboard (as they would be if they clicked the address bar).
Some simple code to detect exit intent on a mobile device.
It detects exit intent through the speed of the user's upwards scroll.
It delays 10 seconds before enabling. You probably should make it about 30 seconds if you only want to show your exit intent popup to people who are really interested in your content.
setTimeout(() => {
document.addEventListener("scroll", scrollSpeed);
}, 10000);
scrollSpeed = () => {
lastPosition = window.scrollY;
setTimeout(() => {
newPosition = window.scrollY;
}, 100);
currentSpeed = newPosition - lastPosition;
console.log(currentSpeed);
if (currentSpeed > 160) {
console.log("Exit intent popup triggered");
document.removeEventListener("scroll", scrollSpeed);
}
};
Is it possible to take a user back to the area of a page where they scrolled down to when pressing the back button in a browser? As in --- pageA is double your screen size (hence you have to scroll to read more). You click a link on pageA to go to a new page - pageB. After reading you click back in browser. Now when you return to pageA you are back at the top and have to scroll down to where you were to continue reading the rest of the page.
Is there a Jquery or JS way to return to that point in the page. Maybe something with .scrollTop()?
If the content is loaded after page "load" event firing, then the back button would not take you back to the position you were. Because the browser scrolls before the 'load' event.
To make the browser remember the scroll position in this case, you have to store the scroll position and status (what content have been loaded) somewhere before navigating away. Either in the cookie, or in the url hash.
If pageA is just a static page without dynamic content (loaded after 'load' event, the browser should remember the scroll position when you go back.
For dynamic content, there at least includes two parts. One is recovering the page status when click "Back" button, so all the dynamic content is loaded, some expander are expanded or collapsed. The other is scroll to there.
The first part depends on how the page is implemented. The 2nd part you can put the scroll top into the cookie when page doing onUnload. For example
$(window).unload(function() {$.cookie('scrollTop',$(window).scrollTop());});
You can do this by using session storage.
$(window).scroll(function () {
//set scroll position in session storage
sessionStorage.scrollPos = $(window).scrollTop();
});
var init = function () {
//return scroll position in session storage
$(window).scrollTop(sessionStorage.scrollPos || 0)
};
window.onload = init;
You can use the following code to detect the scroll position.
$(window).scroll(function (event){
var scroll = $(window).scrollTop();
// Do something
});
Then store scroll in a session and when you click back do scrollTop(scroll) .
This should definitely be done using the History API since it is the only way of knowing for sure that the user went back to the page using the back button of the browser.
First of all, you want to prevent the default scroll restoration of the browser in order to handle it yourself. See this article for details.
if ('scrollRestoration' in history) history.scrollRestoration = 'manual'
Then you need to store the scroll position in the history.state when the user leaves the page. This can be done on beforeunload using history.replaceState.
window.addEventListener('beforeunload', storeScrollPositionInHistoryState)
function storeScrollPositionInHistoryState() {
// Make sure to add lastScrollPosition to the current state
// to avoid removing other properties
const newState = { ...history.state, lastScrollPosition: scrollY }
// Pass the current location.href since you only want to update
// the state, not the url
history.replaceState(newState, '', location.href)
}
or with ES5
function storeScrollPositionInHistoryState() {
var newState = Object.assign({}, history.state, { lastScrollPosition: scrollY })
history.replaceState(newState, '', location.href)
}
Finally, whenever your page is ready to scroll back to its previous position, you check if history.state.lastScrollPosition is defined and if it is the case, you restore the scroll position and remove it from the history.state.
function restoreLastScrollPositionIfAny() {
if (typeof history.state.lastScrollPosition !== 'number') return
scrollTo(scrollX, history.state.lastScrollPosition)
const cleanState = { ...history.state }
delete cleanState.lastScrollPosition
history.replaceState(cleanState, '', location.href)
}
There are still one edge case that is not covered:
The user might have resized the window after leaving the page which can result in an incorrect scroll position when going back to the page. Developers resize the window very often, but real users not that much. That's why I consider it as an edge case.
One way to solve it could be to also store the window size in the history.state and avoid restoring the scroll position if the current window size doesn't match the one stored in the state.
Hope it helps.
After trying #bowen option I have arrived to a better one with smooth scroll and without the problem said by #Frits
$(window).scroll(function () {
//set scroll position in session storage
if ($(window).scrollTop() > 500)
sessionStorage.scrollPos = $(window).scrollTop();
});
var init = setTimeout(function(){
//return scroll position in session storage
if (sessionStorage.scrollPos > 500){
$("html").animate({ scrollTop: sessionStorage.scrollPos },2000);
}
},1000);
window.onload = init;
//For Angular
//Save your scroll position once you scroll
#HostListener('window:scroll', ['$event']) onScrollEvent($event){
sessionStorage.scrollPos = window.scrollY
}
//Scroll to the save value postion
ngAfterViewInit(){
window.scrollTo(0, sessionStorage.scrollPos)
}
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
I have this little function to open/close a popup player:
function popuponclick(popup)
{
my_window = window.open("folder/player-itself.htm", popup, "width=350,height=150");
}
function closepopup()
{
my_window.close();
}
I call the functions from HTML anchors that are on each page of the site (idea is to have the player stopped/started whenever you want)...now...
it works well until i change the page, or refresh the existing one - and from then the window can't be closed anymore. Any idea where i'm wrong? Tested in FF and IE8, same behavior.
Thanks for your help.
When you reload the original window (or tab), everything about the old one is gone, blasted into the digital void, never to be seen or heard from again. The bits literally disintegrate into nothingness.
Thus, the "my_window" reference you so lovingly saved when the second window was opened is gone for good, and the "my_window" variable in the newly-loaded window contains nothing. It's name is but a mockery of the variable in the now-dead page.
The only way to deal with this situation is for the popup window to periodically check back via "window.opener" to see if its parent page has been rudely replaced by some interloper. If that happens (and the new page is from the same domain), then the popup page can restore the reference to itself in the new page's "my_window" variable.
edit — OK here's a sample. You'd put something like this in the popup page, not the launching pages:
<script>
var checkParent = setInterval(function() {
try {
if (window.opener && ('my_window' in window.opener))
window.opener.my_window = window;
}
catch (_) {
// clear the timer, since we probably won't be able to fix it now
clearInterval(checkParent);
}
}, 100);
</script>
That's probably pretty close.