Recently I found very strange(in my opinion) window.scrollTo behaviour in Safari(6.0.5 (8536.30.1), MacOS 10.8.4). It seems it works asynchronously.
My task sounds like:
make some absolute positioned div to be fixed positioned (pin it)
do some page scroll
make previously modified div to be absolutely positioned back (unpin it)
So to unpin this div I have to execute unpin routine just after scroll modification is complete. And here I met the problem. Every browser I checked does it correctly except Safari.
Steps to reproduce:
Open any web page in Safari and make sure it is scrollable at least for 100px and it's initial scroll offset is 0
Open js console in dev tools
execute: window.scrollTo(0, 100); console.log(document.body.scrollTop);
The output is 0. But when I change this code to window.scrollTo(0, 100); window.setTimeout(function() {console.log(document.body.scrollTop)}, 1); the output is 100, as expected.
Here are all other browsers I've tested(where it works fine):
Chrome 27.0.1453.110 (MacOS 10.8.4)
Firefox 21.0 (MacOS 10.8.4)
Opera 12.15 b1748 (MacOS 10.8.4)
IE 8.0.7601.17514 (Win7)
Well, as soon as my code sample is not cross browser, it's easier to check this behaviour on any web page with jQuery:
var $w = $(window);
$w.scrollTop(100);
console.log($w.scrollTop());
VS
var $w = $(window);
$w.scrollTop(100);
window.setTimeout(function() {
console.log($w.scrollTop())
}, 1);
Is this behavior is ok or is it a bug? How to handle it? (Now I modified $.fn.scrollTop to return $.Deferred instead of chaining and resolve it instantly in main thread in all browsers except Safari).
I actually just tried and failed to reproduce your problem even with Safari 6.0.5 (on Lion, i.e. OS X 10.7).
You can run this jsfiddle with https://www.browserstack.com/screenshots to confirm that it works with all Safari versions (5.1, 6.0, 6.1, 7, 8).
Indeed the spec says and I quote:
When a user agent is to perform a smooth scroll of a scrolling box box to position, it must update the scroll position of box in a user-agent-defined fashion over a user-agent-defined amount of time. When the scroll is completed, the scroll position of box must be position. The scroll can also be aborted, either by an algorithm or by the user.
Unless I am reading it wrong, Safari has its right to give you the old value (or indeed anything) while it is animating the scroll. Therefore your setTimeout approach may not even work fine if the browsers want to take it to the extreme.
Setting scroll top in requestAnimationFrame actually solved my issue in browsers.
JavaScript scroll functions generally work synchronously. I had a similar problem with scrollBy() where I've noticed that it was running asynchronously which caused my function to crash. The problem was that the browser had the default CSS-property scroll-behavior: smooth which caused the scroll function to automatically run with requestAnimationFrame() which runs asynchronously. Make sure that the scroll-behavior has the value unset or just overwrite it globally in your CSS like this:
* {
scroll-behavior: unset
}
Related
I'm making a chat interface, so as people chat and the page gets filled, it needs to automatically scroll down to show the newest messages without the user having to manually scroll down. It works in Chrome, but not in Safari. Here is the particular line that is not working
document.getElementById('chatbox').scrollTop = Number.MAX_SAFE_INTEGER;
If the div ID is "chatbox", what do I need to put in the place of this line for it to work in Safari? Also, to clarify, despite it called "scrolltop" it scrolls to the bottom (which is what I want), but only in chrome.
Safari didnt like "Number.MAX_SAFE_INTEGER;". Replaced with an actual integer (ie 1000000) and it autoscrolled.
In this simple example https://jsfiddle.net/4rsje4b6/1/ why is the #test element not being shown before the alert appears?
Shouldn't the jQuery css() method be syncronous?
#test {
display: none;
}
<span id="test">Element</span>
$("#test").css("display", "inline");
alert("Showed element!");
UPDATE:
This behavior is manifesting for me on Chrome Version 52.0.2743.116 m, Windows 10.
It changes the style synchronously, and you will notice that if you read back the value on the next line and show it.
$("#test").css("display", "inline");
alert("Showed element!" + $("#test").css("display"));
But the change of the style object triggers a repaint request message to the page renderer, and that is handled as soon as the browser becomes idle, which is after this script routine has ended.
It depends on the browser, though. In Edge it works fine, and the element is shown right away but in Chrome and Vivaldi it is not.
Another test to see how browsers handle this:
If you resize the browser window, JSFiddle will scale (each of the areas keeps the same relative size). If you resize the Vivaldi browser with the alert open, it doesn't do that. In fact if you make it small, then show the alert, then make it larger, you just get a grey area in the new space until you close the message box. In Edge, the fiddle will just resize in the background, even though the entire browser window is grayed out, so it's not just a matter of the time of processing, but more that Chrome completely freezes the page when an alert is open.
I have a position:fixed Header which I want to center horizontally. So I wrote a function which is executed at the windwo.resize- and document.ready-event to change margin-left of the header. But thats not the point because everything works fine.
Sometimes after my MacBook is closed (hibernating) or I've switched to another Chrome-tab or another OSX-workspace my header isn't centered anymore. It seems like OSX is furtively resizing the window so the CSS Code changes, but it never changes back without resizing the browser window manually. But the problem occurs not every time...
Thats why I want to execute some code after my window is focused again to prevent from this ugly behavior.
Another idea: Does it maybe have to do with the difference between the document.resize- and window.resize-event? What should I use?
I am experiencing very strange Google Chrome behavior.
In my JavaScript I have scrollTo on page load that scrolls to particular part.
The code is simple as:
$('body').animate({ scrollTop: $('nav ul').position().top }, 1000);
But the problem is that when it scroll the page Google Chrome reload the page and that JavaScript is not firing again.
Maybe some one experiencing that before and have a solution or an idea why that is happening?
Thank you!
P.S. forgot to give an live example (do not take as advertising) - csspandemic.com
P.P.S. As people suggested it is working fine on Windows and happening only on OSX. (I changed the title.)
Looks like it's a bug in Chrome: http://crbug.com/61674. Chrome isn't reloading the page -- it's restoring the scroll position to where it was the last time the page was loaded. If you scroll to a different position in the page and then refresh, you will see that the jump is to that last position; conversely, if you load the page in incognito mode, it works fine, because there isn't any cached scroll position.
Unfortunately, I'm not aware of a good workaround for this. I tried changing location.hash in an attempt to invalidate the cached scroll position, but to no avail.
In our product, we're using the most recent development version of jQuery Mobile in our ASP.NET website. Each and every time we do an ASP.NET postback, the browser window goes to the back of the screen.
Example:
Maximize any window. Example: Visual
Studio, Word, Windows Explorer.
Maximize IE9 over it. IE9 is the only
thing you see on the screen.
Click on a button in our solution that does
a postback.
IE9 is no longer visible.
Whatever was behind it now has focus
(and fills the screen, as it is
maximized)
Only workarounds I know:
Don't include the jQuery mobile scripts.
Ensure IE9 is the only maximized window in Windows.
I don't know what jQuery Mobile is doing in the background and am assuming this is a bug in IE9 that will eventually be fixed. However, if you had any tips on how to prevent it from happening in the meantime, that would be great.
Edit: Seems it isn't on every postback. It is on every postback that performs a Response.Redirect. I should add that all my postback are actually utilizing ASP.NET AJAX, not full postbacks.
I know this is an old post, but for people coming here from Google:
I ran into this same issue today. It seems this lose focus behavior is what IE does when you trigger the blur event on the window object. This was the code that caused this issue for me:
$(document.activeElement).blur();
activeElement will default to the body element when there are no other elements in focus, and the blur event then bubbles up to the window. To fix this I simply did a check like:
if (document.activeElement != $('body')[0]) {
$(document.activeElement).blur();
}
I had similar problem with IE10 and jQuery 1.7.2.
I found these lines in my code:
$(document.activeElement).blur();
and
$(':focus').blur();
So, adding simple .not('body') resolves the problem:
$(document.activeElement).not('body').blur();
$(':focus').not('body').blur();
This same issue seems to occur with jQuery Mobile 1.4.2.
When using IE 10, with a single tab open and another window on the same monitor, if you open a popup it will send the browser to the background.
To fix this you have to edit the _handleDocumentFocusIn function. You need to change the line(10391) that reads:
target.blur();
to
if (targetElement.nodeName.toLowerCase() !== "body")
{
target.blur();
}
I made a pull request so hopefully this will be included in the next version.
Just posting this link to anybody who is experiencing more of this continued mess. I am seeing the problem on IE 9 and IE 10 on a window.location = 'BLAH', from within the Angular location resource.
This doesn't seem to solve the problem for me, but it may help others:
http://support.microsoft.com/kb/2600156/en-us