I've built a fairly simple site that utilizes pjax to load content. My problem is: once a user scrolls to say... the middle of any given page and performs a refresh, the page reloads starting at the top, then jumps down to whatever distance from the top the user was at when they refreshed.
My question is: how can I hide ALL document content after a refresh, then fade everything in after a short timeout (half a second, for instance) to avoid the jarring page jump?
Any help/advice is much appreciated!
You can set the content to display: none; in your CSS initially and have an onready handler call .fadeIn(): https://jsfiddle.net/19e14sev/
$(function() {
var secondsToWait = 2;
setTimeout(function() {
$('#content-selector').fadeIn();
}, secondsToWait * 1000);
});
Related
I have a navigation bar and I've set its position to change to fixed when the user scrolls down past it and vice versa when the user scrolls up past that point by using the following waypoint:
var $navbar = $('.navbar-default');
$navbar.waypoint(function(){
if ($('#navigation-bar').hasClass('navbar')){
$('#navigation-bar').toggleClass('navbar-fixed');
} else{
($('#navigation-bar').toggleClass('navbar'));
}
}, { offset: '28%' });
This ensures the navbar stays on the users screen only past a certain point. This works as intended most of the time, however the issue is if the user scrolls down past that waypoint and then refreshes the page the navbar will jump back to its original position, which then causes undefined behaviour if you scroll back up past it.
Is there a way to ensure everything that is on the screen remains at that exact same spot when the user refreshes?
You can use the window.scrollTo function when the page loads
//scrollTo(x, y)
window.scrollTo(0, 0);
//the rest of your code...
This will scroll to the top-left of the page everytime the page loads.
Edit:
The answer from this question may also work:
* {
overflow-anchor: none;
}
I use the following code on page load to smoothly scroll to a div
$(document).ready(function() {
$('html,body').delay(50).animate({scrollTop:jQuery('#3342').position().top-10}, 'slow');
});
It works wonderfully to smoothly scroll the page to a predefined div id (in this case div id=3342, but the actual div ID changes depending on what button the user clicks).
The problem is that if there are any images in the pages above div 3342, then after the scroll finishes, the page jumps and the entire positioning scroll is for nothing, as that content is no longer on screen.
This is on mobile safari btw. I know Google chrome has recently introduced Scroll anchoring, and I believe this is the functionality i'm trying to reproduce somehow.
Just FYI, I have no way of knowing the sizes of images or the ratio of the image sizes ahead of time. They are random images from around the web
Thanks!
EDIT: I don't want to change to window/load event as that means I would have to wait for all the images to load first, which would delay the scroll event massively on some pages
EDIT: The image URLs are all on the source page, no ajax loading of pages after the fact
Repeat until complete:
$(document).ready(function() {
var div = jQuery('#3342');
var complete = false;
function adjust () {
if (!complete) {
$('html,body').delay(50).animate({scrollTop:div.position().top-10}, 'slow', adjust);
} else {
$('html,body').delay(50).animate({scrollTop:div.position().top-10}, 'slow');
}
}
adjust();
$(window).on('load', function () {
complete = true;
});
});
So i currently have a setup that allows for a button to be pressed, the current content is hidden, and more content scrolls in from the right. However my problem is that for the briefest of moments the footer, which sits below the content, moves up before moving back down below the content just loaded in.
This fiddle best illustrates the problem: http://jsfiddle.net/9Dubr/766/
My Code:
$('#rightButton').click(function(){
var toLoad = 'page.html #content';
$('#content').hide("fast", loadContent);
function loadContent() {
$('#content').load(toLoad,'',showNewContent);
}
function showNewContent() {
$('#content').show("slide", {direction: "right" }, 1000 );
}
return false;
});
Thanks for your help
The fiddle doesn't seem to work for me, but it sounds to me like your footer is simply trying to occupy the empty space left behind by the previous content. In which case, you can try giving the parent container of your content a fixed height just before hiding it. You can then unset the height once the next content is loaded, that way there isn't really any empty space for the footer to try and occupy.
Untested code:
$('#content').parent().css({height: $('#content').height()});
$('#content').hide("fast", loadContent);
...
function showNewContent() {
$('#content').show("slide", {direction: "right", complete: function() {
$('#content').parent().css({height: ''});
} }, 1000 );
}
If you'd like to make it more visually appealing, you can animate the height so the footer will get pushed/pulled more smoothly.
Hope this helps.
It may be because the page is allowed to resize the lengths of divs. A few suggestions that might work is:
Quick Fixes:
Hiding your footer until the person is at the bottom of the screen
Making your footer a static size and maybe even making the footer position final.
Adding a fixed size container around your objects as mentioned in a previous comment.
This way atleast it won;t bother the footer in any way.
Fix without changing footer:
It is obviously a load problem when the button itself is pressed. Because as I understand from your code when the button is pressed and then you are adding this new content to your page right before using the slide effect.
I would suggest you preload the content when first opening the page and then just use the .slide() when the button is pressed.
I have two navigations on my site, they are both on the top and essentially do the same thing.
I want the main (smaller) navigation to appear on the page when the page originally loads and it hasn't been scrolled on.
Once the page scrolls and the main navigation is no longer visible, I want the secondary navigation (larger) to appear and be fixed to the top of the page.
I already have the fixed to top portion worked out, I just need help with the fading in and out on the page scroll part.
The main Navigation has an id of: navMain
The Second Navigation has an id of: navSecondary
I found this script on Stackoverflow but it doesn't seem to be doing exactly what I want.
$(window).scroll(function() {
var pxFromBottom = 350;
if ($(window).scrollTop() + $(window).height() > $(document).height() - pxFromBottom) {
$('#navSecondary').fadeOut('slow');
} else {
$('#navSecondary').fadeIn('slow')
}
});
This script allows both navigation menues to appear at the same time when the page originally loads and once you scroll the page the secondary navigation fades away and never comes back even if you scroll back to the top of the page.
If you want to you can see exactly what I'm talking about here:
http://www.green-panda.com/contact.php
I have an iframe from the middle to bottom on a page. When I load the page it scrolls to the bottom. I tried to body onload window.scroll(0,0) but it does an ugly effect because it first goes down and then immediately scrolls up.
What's the cause of this automatic scroll to bottom with iframe on the page?
This is just a random one, but possible doing something like this:
<iframe style="display: none;" onload="this.style.display='block';" src="..."></iframe>
The thinking being that if it is some focus stealing script on a remote page that you can't control, the browser won't focus a hidden element. And there's a good likelihood that your onload will fire after their focus changing script.
Or, one other option that might be a bit more reliable:
<iframe style="position: absolute; top: -9999em; visibility: hidden;" onload="this.style.position='static'; this.style.visibility='visible';" src="..."></iframe>
Here we're basically saying hiding the frame and moving it to a negative offset on the page vertically. When it does try to focus the element inside of the frame, it should scroll the page upward, then once loaded place the iframe back in it's intended position.
Of course, without knowing more, it's hard to say for sure which tradeoffs are okay, and both of these options have conditions that are a tad racy, so YMMV.
I hope that helps :)
I came up with a "hack" that works well. Use this if you don't want your webpage to be scrolled to anywhere except the top:
// prevent scrollTo() from jumping to iframes
var originalScrollTo = window.scrollTo;
window.scrollTo = function scrollTo (x, y) {
if (y === 0) {
originalScrollTo.call(this, x, y);
}
}
If you want to disable autoscrolling completely, just redefine the function to a no-op:
window.scrollTo = function () {};
Similar method but using classes.. I added a class to the iFrame's parent div of "iframe_display" with a style inside that of visibility: hidden. On page load I then used jQuery to remove the class
.iframe_display{visibility:hidden}
$(function(){
$('#iframe_wrapper').removeClass('iframe_display');
});
This takes the focus away from the iFrame and stops the scrolling down to the iFrame on page load
Simple. Use about:blank in src like
<iframe id="idName" name="idName" src="about:blank" style="display:none"></iframe>
The src="about:blank" trick provided by Leandro & edited by Spokey worked for me, but I'd like to share a workaround I was using before.
A temporary solution I found was to embed the iframe in the uppermost element on my page (nav, header etc), so that even if the browser wants to jump to focus, it 'jumps' to the top element. This still can cause a slightly perceptible jump, which might bug you.
To make sure the iframe remains hidden if you choose to place it near the top of a page, I applied an inline style of style="visibility:hidden; height: 0px; width: 0px;". I guess you could also use a z-index combo.
This seems to work well:
<iframe src="http://iframe-source.com" onLoad="self.scrollTo(0,0)"></iframe>
This is the solution I came up with and tested in Chrome.
We have an iframe wrapped by a div element. To keep it short, I have removed the class names related to sizing the iframe. Here, the point is onMyFrameLoad function will be called when iframe is loaded completely.
<div class="...">
<iframe onload="onMyFrameLoad()" class="..." src="..."></iframe>
</div>
Then in your js file, you need this;
function noscroll() {
window.scrollTo(0, 0);
}
// add listener to disable scroll
window.addEventListener('scroll', noscroll);
function onMyFrameLoad() {
setTimeout(function () {
// Remove the scroll disabling listener (to enable scrolling again)
window.removeEventListener('scroll', noscroll);
}, 1000);
}
This way, all the scroll events become ineffective till iframe is loaded.
After iframe is loaded, we wait 1 sec to make sure all the scroll events (from iframe) are nullified/consumed.
This is not an ideal way to solve your problem if your iframe source is slow. Then you have to wait longer by increasing the waiting time in setTimeout function.
I got the initial concept from https://davidwells.io/snippets/disable-scrolling-with-javascript/