On Chrome, when I refresh while not at the very top of the page, the $(window).one('scroll' function is triggered immediately upon page load. I have a landing page that disappears when the user scrolls. But the landing page is disappearing immediately if I refresh the page while not at the top.
I tried adding
document.body.scrollTop = 0;
document.documentElement.scrollTop = 0;
above the $(window).one('scroll' but that didn't work.
How can I reset the page to the top BEFORE Chrome reads the $(window).one('scroll' function?
Or is there a better solution?
That's actually correct behavior, the browser will scroll the page, and in normal circumstances we want to know about it, so it's normal the event is fired.
Unfortunately, when this event will fire isn't very well specified, so we have to resort on some magic numbers like
onload = (evt) => setTimeout(() => {
addEventListener("scroll", callback, { once: true });
}, 1000); // hopefully 1s after full page load the browser will have computed the new scrolling position
but that may very well fail, moreover if there is a lot of content being dynamically added in the page at load time.
If this is a deal breaker for you, maybe you'd be interested in preventing the page from restoring the scroll position at load, for this you can use history.scrollRestoration = "manual".
Another option would be to only listen to scroll events that do happen inside your landing page, instead of listening to every ones that happen in the page, and to reset this wrapper's scroll position after you hide the landing page, so that at the next reload the browser doesn't need to restore it.
Related
I have a single page website. If click one of the navbar tabs, lets say 'contact us' the site will scroll down to the contact section. The problem is, if I refresh the site now it will automatically scroll down to the contact section each time. I want the site to scroll to the top of the page every time I refresh. The reason this is happening is because the address bar is changed to ...index.html#contact-area.
I tried the code below but the site gets caught in an infinite refresh loop.
<script>
window.location.replace("index.html");
</script>
I also tried the following but it doesn't work. It starts to scroll up then stops.
<script>
window.onbeforeunload = function () {
window.scrollTo(0, 0);
}
</script>
One option is to attach an event listener to the anchor instead, and instead of changing the page hash, call scrollIntoView on the #contact-area:
anchor.addEventListener('e', (e) => {
e.preventDefault(); // don't change page hash (unless JS disabled...)
document.querySelector('#contact-area').scrollIntoView();
});
I want to navigate inside the page with an animation using Javascript, but also change the URL so the user can click "back" to go back to the previous "page".
I have no idea how to approach this. Do I put the content I'm navigating to on a new html page, or on the same page?
What I've tried so far:
Some Other Page
This will completely reload to someOtherPage, and won't allow animations.
Some Other Page
<script>
function animateToOtherSection() {
//things like fade in/out or scroll
}
</script>
This works if the content I'm navigating to exists in this page, which is okay, but the URL won't be changed (except for the additional #).
If i try to change window.href in Javascript, the entire page reloads, which is not desired.
This question was inspired by some websites like this. When the See our projects button is clicked, although it as an anchor element, the page doesn't reload, but a fade out/in executes and the navigation bar above stays throughout. If I click the 'back' button in my browser, another animation takes me back to the splash screen.
Note: This is not an option:
Some Other Page
I don't want to just scroll to an element, but manipulate and show/hide a lot of elements on the screen.
Thanks in advance for the answers!
The DOM window object provides access to the browser's history through the history object. It exposes useful methods and properties that let you move back and forth through the user's history, as well as -- starting with HTML5 -- manipulate the contents of the history stack.
https://developer.mozilla.org/en-US/docs/Web/API/History_API
Load data from the server and place the returned HTML into the matched element.
http://api.jquery.com/load/
You can make it easy here is example:
HTML:
<button id="changeUrl">See our projects</button>
JavaScript:
$('#changeUrl').click(function () {
history.pushState({}, 'Title', '/Url/Test');
$(document).load('/url html');
});
Also you can add animation for example :
$('#changeUrl').click(function () {
$('body').fadeOut();
history.pushState({}, 'Title', '/Url/Test');
$(document).load('/url html', function () {
$('body').fadeIn();
});
});
You may also add a JavaScript "fadeout" animation when "unloading" the current page, and a "fadein" animation executing at the begining of the next page load.
If you prefetch most of your content, the transition will be smooth.
To avoid a page load when you click on a link, attach an onclick event to your link, and finish your JavaScript callback by a e.preventDefault(); as explained in this question : How to stop default link click behavior with jQuery from Mozilla Dev Network : https://developer.mozilla.org/en-US/docs/Web/API/event.preventDefault
Cancels the event if it is cancelable, without stopping further propagation of the event.
About link prefetching : https://developer.mozilla.org/en-US/docs/Web/HTTP/Link_prefetching_FAQ
<link rel="prefetch" href="/images/big.jpeg">
Or even really loading <img with a style=display:none; to hide them…
The Feature I Want:
I want to give a user a link like mysite.com/foo#bar so when they hit this link they land on the page foo and are scrolled half way down the page to the content with the id bar. It should be noted that this link will always be clicked from off site or typed into the address bar manually, the user will not already be on the page with all assets loaded.
Also fyi I am using angular and the page in question each bit of content is in an element directive, and in each directive template there are images
The Issue:
Easy enough right? Well I'm running into some problems, most of the time it works, but maybe 40% of the time it doesn't and the user lands above the content, I believe this is because the browser scrolls to the correct point on the page, but then slightly afterward images are loaded in above it pushing the rest of the page down, leaving the user in a random unintuitive spot. (For some reason the failure rate seems to be worse on iPhones...)
What I've Tried So Far:
In a run function I look for a hash fragment on any route and scroll to it if it exists.
if($location.hash()) {
$anchorScroll();
}
I've tried:
Wrapping it in a timeout
This works sometimes but is obviously not consistent, sure I can set it to 500ms and on a great wifi connection it's fine, but not on a mobile with poor signal
listening for $viewContentLoaded
Too fast, ui-router seems to fire this event way before the page is rendered
Emitting an event in each post-link function for all directives on the page.
link: function ($scope) {
$scope.$emit('loadingFinished');
Then picking that up again in the run function
$scope.$on('loadingFinished', function () {
$timeout(doAnchorScroll, 500);
}
This raised the success rate but still wasn't foolproof. And I witnessed it leaving the user stranded in weird spots mainly on iPhones.
Can anyone suggest a way of detecting a moment where it is safe to scroll, or perhaps some other way of ensuring landing in the correct spot?
Two things - first is a user-scroll should prevent it - you don't want to be scrolling the view if they've already scrolled. Second is listening for the images to finish loading.
Listening for the images is quite easy:
$("img").one("load", $anchorScroll);
Then in $anchorScroll I'd suggest checking if all images have loaded, and returning immediately if not (bonus points if you only check images above the anchor - but only doing a quick reply):
var scrolled = false;
function $anchorScroll() {
var allLoaded = true;
$("img").each(function() {
if (!this.loaded) {
return allLoaded = false;
}
});
if (scrolled || !allLoaded) {
return;
}
...
The scrolling is possibly slightly harder - you can check for scroll events, but they are slightly different between platforms - and might even get fired for the manual scroll - if you find that happens then simply have a global that says "I'm scrolling here" and ignore it, otherwise:
$(document).one("scroll", function() { // Use ".on" if this gets fired for code...
scrolled = true;
});
Note that you probably don't need to care about failed image loads, or ones that have already loaded, since your initial call to $anchorScroll() will catch them.
I would like to prevent the user to access subpages of my jqm page. To do that I use the pagebeforecreate event to check a certain condition and depending on that, change the page displayed (cancel current pageload and redirect or normally load the current starting/main page). The Problem is, that I still see the page flickering up before the changePage() is executed even when I call the preventDefault() method. I also used a relative URL as the first parameter (to = 'page.php') of the changePage(to, options) and since my #subpage1 lies within the page.php it should open - which it did - but then the transitions are broken because no real refresh was done.
Note that I have a page.php including different #subpage's (such as #subpage1, #subpage2).
jQuery(document).on('pagebeforecreate', '#subpage2', function(event, data) {
if (!isCondition1() && !isCondition2()) {
// stop loading #subpage2
event.preventDefault();
jQuery.mobile.changePage(jQuery('#subpage1'), {
data: 'lang=de¶m1=foo¶m2=bar',
reloadPage: true,
type: 'get'
});
}
// go on loading #subpage2
});
jQuery(document).one('pageinit', '#subpage2', function() {
// do something
});
Have you tried setting the body style to display:none in the html? And then if the page loads correctly you can set it's display property? That should be a 'workaround' to prevent the flicker of the page?
I'm designing an HTML page which has one button. The user clicks the button and a simple jQuery script animates that div away, revealing lower page content. You can see it here.
I've noticed that it looks/works fine the first time, but if I refresh the page with the browser button, it doesn't fully reset. The initial container is only half on the page. If I enter the URL again and load the page, it resets as expected.
NOTE: This only happens if you scroll down a bit after clicking the initial button... which seems weird.
I had no idea that there was any difference between these two operations, but there clearly is. What is the difference and how can I fix this problem from happening?
Here's my jQuery code, in case it's relevant:
$(document).ready(function(){
var faqs = $("#FAQ");
$("#learnmore").click(
function(){
$("#home").animate({top:'-=1066px'},600);
$("#more").animate({top:'-=1066px'}, 600, function() {$("#background").hide();} );
$("body").css('overflow-y', 'scroll');
//$("#home").slideUp();
console.log("jquery loaded");
}
);
});
It happens because it is cached by the browser.
If you styles are regularly modiefied, then as easy fix is to attach a unique id on the end of the reference, like
<link href="style.css?time=168768234928" ..../>
What it does, it makes the browser think it is a new request everytime it loads.
It happens because browser trying to scroll to the same position, what was before page reload. To check it, try press button and don't scroll to bottom of page and then reload page.
Okey, the reason is clear.
Now we need solution. Try this:
#more {display:none}
in your css. And then use
$("#more").show().animate(...
in your $("#learnmore").click() function. I hope this will solve the problem.