I'm running into a problem that's actually a "feature" on Chrome.
As most of you might know, Chrome remembers a scroll position that it returns to, whenever you come back to a page. And I kind of have a problem with that.
Is there any way to override this without the user noticing?
Mees
Failed try-outs:
ScrollTop on document.ready
In Chrome 46+, the auto scroll behavior can be turned off using history.scrollRestoration:
if ('scrollRestoration' in history) {
history.scrollRestoration = 'manual';
}
source: https://developers.google.com/web/updates/2015/09/history-api-scroll-restoration
I've checked on chrome, it worked well. Sometimes setTimeout does trick :)
<script type="text/javascript">
window.onload=function(){
setTimeout(function(){
scrollTo(0,-1);
},0);
}
</script>
x = 0; //horizontal coord
y = document.height; //vertical coord
window.scroll(x,y);
Some Javascript like that may very well be able to be manipulated to stop the auto scrolling.
It depends though, are you happy for the scroll to be simply set to automatically go to the top, or are you actually looking for the Chrome standard option to take the page to last scroll position, to be turned off completely?
What are you currently attempting to use for scrollTop()?
I solved this by attaching to scroll event, and then resetting scroll position the first time a user scrolls. Works for on-spot reloads for me.
Looks like this:
var scrollResetOnce = false;
$(window).on("scroll", function() {
if (scrollResetOnce) return;
scrollResetOnce = true;
scrollTo(0, -1);
});
Here is a clean way of getting this done.
window.addEventListener('unload', function(e){
document.body.style.display = 'none';
});
By simply setting the body display to 'none' you don't have to worry about a flash of the browser scrolling to the top of the page before it is unloaded and the scroll position will automatically be reset to 0.
Related
Hello Coders! I am coding a chat system, I would like the scroll bar to stay at the bottom. In this way when someone sends a message the user would not have to scroll down. I would also like it to start at the bottom of the page load. Additionally, the user can scroll up when needed, but when they scroll back down it locks in place. I have tried many times but for some reason it does not work, I was wondering if anyone has a method of doing this?
I've also have struggled with implementing this for a while. The approach I've ended up with relies on using MutationObservable
MutationObservable allows to watch for DOM changes inside element and perform some actions when deeply nested element is changed (in your case, for example, new comment was rendered):
// chatContainer is reference to your chatContainer element
var isLocked = true;
var mutationObserver = new MutationObserver(() => {
if (isLocked) {
scrollToBottom();
}
});
mutationObserver.observe(chatContainer, {
childList: true,
subtree: true,
attributes: false,
});
This gave me a callback, where I likely had to make chatContainer scroll to the bottom.
Scroll to the bottom implementation could be:
function scrollToBottom() {
chatContainer.scrollTop = 99999999999;
}
To change isLocked flag, I had to listen for user scrolls on chatContainer and update it accordingly:
var LOCK_OFFSET = 25; // how many pixels close to bottom consider scroll to be locked
chatContainer.addEventListener('scroll', handleUserScroll);
function handleUserScroll() {
var scrollFromBottom =
chatContainer.scrollHeight -
chatContainer.scrollTop -
chatContainer.clientHeight; // how many pixels user scrolled up from button of the chat container.
isLocked = scrollFromBottom > LOCK_OFFSET; // set new isLocked. lock, if user is close to the bottom, and unlock, if user is far from the bottom.
});
Hope I've explained the general idea. This approach works fine for me. User scroll listening should be improved with events debouncing. And don't forget to dispose scroll event and mutation observer subscriptions.
This is what I've used in my projects. It works on IE, Edge, Firefox, Chrome and Opera. I'm not sure about Safari.
var a = document.querySelector('#divchat');
a.scrollIntoView(false);
I hope it helps.
There are a lot of answers for this question around.
Here is one of them from Automatically scroll down chat div
The main point of that answer is the variables scrollHeight, scrollTop, and clientHeight can be manipulated.
But basically, to scroll down it is to use container.scrollTop = container.scrollHeight;
Safari for desktop automatically scrolls the page to any input element that I focus from javascript. This behavior can be seen right here:
https://codepen.io/anon/pen/JmKPwZ
I have found no way to prevent this automatic scrolling. However, there is a known workaround - save the screen position first and scroll back to that position after focusing:
var el = document.getElementById("editable");
var x = window.scrollX, y = window.scrollY; // save position
el.focus();
// manipulate selection inside the focused element with `document.createRange()`
// and do other stuff
window.scrollTo(x, y); // restore position
This workaround used to work fine in Safari 10 and stopped working in Safari 12. Calling scrollTo after focusing doesn't do anything anymore. However, if scrollTo is executed with a delay (even a really short one), everything works:
var el = document.getElementById("editable");
var x = window.scrollX, y = window.scrollY; // save position
el.focus();
// manipulate selection inside the focused element with `document.createRange()`
// and do other stuff
setTimeout(function() {
window.scrollTo(x, y); // restore position
}, 1);
But with this 1-millisecond delay one can see the page first scrolls to the input field and then very quickly back to the original position, so the new workaround is far from perfect.
Is there any way to gracefully prevent desktop Safari from scrolling the page to focused element automatically or at least a good workaround to mitigate that behavior?
After much poking around I've stumbled upon a solution that works:
var el = document.getElementById("editable");
var scrollTop = document.body.scrollTop; // save position
el.focus();
// manipulate selection inside the focused element with `document.createRange()`
// and do other stuff
document.body.scrollTop = scrollTop;
For some reason saving document.body.scrollTop works, while saving window.scrollX and window.scrollY doesn't.
I just had the same bug and was able to get my version working with:
setTimeout(function() {
window.scrollTo(x, y);
}, 0);
I think maybe that in Safari 12 (for some reason) the focus method in the HTMLElement Web API takes longer to run than the scrollTo method in the Window Web API. If this is the case, then there ends up being a race condition between the completion of the focus method and the scrollTo method, resulting in the scroll position staying at the focused element.
Using setTimeout with a delay of 0ms essentially just says "Run this once everything in the call stack is done executing," which seems to fix the issue for me.
Here's a video I used as a resource when debugging:
https://www.youtube.com/watch?v=8aGhZQkoFbQ
Hope this helps!
you can use the preventScroll options to do this.
current?.focus({
preventScroll: true,
});
...without limiting the scroll inside the iframe or the need to specifically name/tag all scrollable elements.
Imagine google maps widget embedded in parent page. When you zoom in the widget you don't want the parent page to scroll, obviously.
I thought an answer to my previous question solved the problem:
While scrolling inside an iframe, the body doesn't know anything about
what happens there. But when iframe scroller reach the bottom or the
top, it pass scrolling to body.
Cancel the event that propagates from the iframe.
But the solution does not work in Firefox because Firefox will not - by design - propagate events captured by iframe to the parent page, yet strangely it will scroll the parent page. See jsfiddle here.
$('body').bind('mousewheel DOMMouseScroll', onWheel);
function onWheel (e){
if (e.target === iframe)
e.preventDefault();
console.log(e);
}
So, how do I prevent page from scrolling when user zooms content in embedded iframe, in Firefox?
Since it is a bug in Firefox, the workaround is to work directly with the scroll event, instead of the mousewheel / DOMMouseScroll ones.
The way I did: When user enters the mouse over the iframe, I set a flag to true, and when he leaves the mouse out there, I set it back to false.
Then, when user tries to scroll, but the mouse arrow is inside the iframe, I prevent the parent window scrolling. But, unfortunately, you can't prevent the window scrolling with the usual e.preventDefault() method, so we still need another workaround here, forcing the window to scroll exactly to the X and Y positions it was already before.
The full code:
(function(w) {
var s = { insideIframe: false }
$(iframe).mouseenter(function() {
s.insideIframe = true;
s.scrollX = w.scrollX;
s.scrollY = w.scrollY;
}).mouseleave(function() {
s.insideIframe = false;
});
$(document).scroll(function() {
if (s.insideIframe)
w.scrollTo(s.scrollX, s.scrollY);
});
})(window);
I've created an immediately executed function to prevent defining the s variable in the global scope.
Fiddle working: http://jsfiddle.net/qznujqjs/16/
Edit
Since your question was not tagged with jQuery (although inside it, you've showed a code using the library), the solution with vanilla JS is as simple as the above one:
(function(w) {
var s = { insideIframe: false }
iframe.addEventListener('mouseenter', function() {
s.insideIframe = true;
s.scrollX = w.scrollX;
s.scrollY = w.scrollY;
});
iframe.addEventListener('mouseleave', function() {
s.insideIframe = false;
});
document.addEventListener('scroll', function() {
if (s.insideIframe)
w.scrollTo(s.scrollX, s.scrollY);
});
})(window);
Given all the prerequisites, I think the following is the sanest way to make this work in Firefox.
Wrap your iframe with a div which is a little bit shorter to enable vertical scrolling in it:
<div id="wrapper" style="height:190px; width:200px; overflow-y: auto; overflow-x: hidden;">
<iframe id="iframeid" height="200px" width="200px" src="about:blank">
</iframe>
</div>
Now you can center the iframe vertically and re-position it every time
the wrapper receives a scroll event (it will occur when a user tries to scroll away at frame edges):
var topOffset = 3;
wrapper.scrollTop(topOffset);
wrapper.on("scroll", function(e) {
wrapper.scrollTop(topOffset);
});
Combine this with your previous fix for Chrome, and it should cover all major browsers. Here is a working example - http://jsfiddle.net/o2tk05ab/5/
The only outstanding issue will be the visible vertical scrollbar on a wrapper div. There are several ways to go about it, for instance - Hide scroll bar, but still being able to scroll
I think that will solve your problem
it solved mine
var myElem=function(event){
return $(event.toElement).closest('.slimScrollDiv')
}
$(document).mouseover(function(e){
window.isOnSub=myElem(e).length>0
})
$(document).on('mousewheel',function(e){
if(window.isOnSub){
console.log(e.originalEvent.wheelDelta);
if( myElem(e).prop('scrollHeight')-myElem(e).scrollTop()<=myElem(e).height()&&(e.originalEvent.wheelDelta<0)){
e.preventDefault()
}
}
})
replace '.slimScrollDiv' with the element selector you want to
prevent parent scroll while your mouse is on it
http://jsbin.com/cutube/1/edit?html,js,output
On refreshing a long HTML page, the scroll position is initialized to the top and then jumped to the last scroll position.
Is there a way to stop this scroll jump behavior on refresh and just initialize scroll position to last scroll position?
How about use html5 localStorage function.
window.addEventListener('scroll', function () {
localStorage.scrollX = window.scrollX;
localStorage.scrollY = window.scrollY;
})
window.addEventListener('load',function () {
window.scrollTo(localStorage.scrollX || 0, localStorage.scrollY || 0);
})
Check it on http://jsfiddle.net/g5NKG/10/show/
It sounds like you may need the .scrollTop() method from jQuery found here
So:
$(document).ready(function(){
$(this).scrollTop(0);
});
From link in comments, this also is a quick fix:
$(document).scrollTop(0);
Isn't this just default browser behavior? What you're describing sounds like all mayor browsers are already doing it like that.
I want to check if page is scrolled after it has finished loading and I'm using this code:
$(document).ready(function(){
alert($(window).scrollTop());
});
It works well in Firefox but allways returns 0 in Chrome. Why is this?
Actually Firefox is the only browser that doesn't return 0 for $(window).scrollTop() on domReady or window.onload. Chrome, Safari and IE all return 0. The only safe way to get correct position of scrollbar on domReady is, as mentioned in another answer above, to set an event handler on window's scroll event as below:
$(document).ready(function(){
$(window).scroll(function() {
console.log($(window).scrollTop());
$(window).unbind('scroll');
});
});
$(window).scrollTop() will return 0 when the window isn't scrollable.
The chrome restores the pre-refresh scroll position once the DOM is loaded. So, getting scrollTop on scroll event instead of ready event will work.
I also had the problem that scrollTop() always returned 0 in Chrome, whether I used it on window, on document or on 'html,body'. I finally found out that css was the problem:
html, body {
height: 100%;
overflow-x: hidden;
}
Actually, I don't know exactly why because you can remove parts of this code and then it works again. Strange but problem solved ;)
Try the following code in a page that has some text and a link in the bottom of the page. Remember to have enough text or blank lines in order to make a scroll of the page until you can see the my button
$(document).ready(function () {
alert($(window).scrollTop()); // first load if you did not scroll = 0
$("#button").click(function () { alert($(window).scrollTop()); });
// hitting the button that is located on bottom of page
// - i had to scroll the page = xxx (68 in may case)
});
It is normal in your case to get 0 because the page is not scrolled, the offset between your position and the top of the page is 0.
I tried in Chrome, FF6, IE9.
I hope i was helpful.
I had the same problem but got fixed by adding the document declaration:
<!DOCTYPE html>