Has anyone tried using
$(“html, body”).animate({scrollTop:0}, 'slow');
on Opera browser?
It does a weird effect especially if you scroll on a long page, it seems like the page go first to the top and then it scroll down to the right point. It is a weird disturbing effect...
Is there any workaround to fix it? thanks
The attribute was not defined properly in the past. It was introduced by IE, I think, then reverse engineered to be implemented by different user agents. It has been since described in CSSOM (still a working draft). As of today, there is still a bug indeed in Opera which is being in the process to be fixed.
## Possible hack.
A solution will be
$(window.opera?'html':'html, body').animate({
scrollTop:0}, 'slow'
);
Be careful because if Opera fixes it at a point, the code is likely to behave strangely.
Why?
In Firefox and IE quirks mode, you have to set the property on the "body" to make the page scroll, while it is ignored if you set it on the "html".
In Firefox and IE standards mode, you have to set the property on the "html" to make the page scroll, while it is ignored if you set it on the "body".
In Safari and Chrome, in either mode, you have to set the property on the "body" to make the page scroll, while it is ignored if you set it on the "html".
Since the page is in standards mode, they have to set it on both the "html" and "body, or it won't work in Safari/Chrome.
Now here's the bad news; in Opera, when you read the scrollTop of the body it is correctly 0, since the body is not scrollable within the document. But Opera will scroll the viewport if you set the scrolling offset on either the "html" or "body". As a result, the animation sets two properties, once for the "html" and once for the "body". The first starts at the right place, while the second starts at 0, causing the flicker and odd scroll position.
Better solution not involving user agent sniffing
From http://w3fools.com/js/script.js
// find out what the hell to scroll ( html or body )
// its like we can already tell - spooky
if ( $docEl.scrollTop() ) {
$scrollable = $docEl;
} else {
var bodyST = $body.scrollTop();
// if scrolling the body doesn't do anything
if ( $body.scrollTop( bodyST + 1 ).scrollTop() == bodyST) {
$scrollable = $docEl;
} else {
// we actually scrolled, so, er, undo it
$body.scrollTop( bodyST - 1 );
}
}
This http://www.zachstronaut.com/posts/2009/01/18/jquery-smooth-scroll-bugs.html#opera might be a better solution without using any Opera specific functions and accounting for quirks mode.
$("body:not(:animated)").animate({ scrollTop: destination}, 500 );
return false;
works for me, in opera as well.
EDIT: does not work in firefox though
I've had this problem, too. This is what I use and it works. It's not browser sniffing, but it's not particularly nice code, to me. It works tho, for now.
Calling scrollTop on html element in Opera 11 / IE 8 / FF 3.6 returns a number larger than zero
Calling scrollTop on html element in Chrome 10 / Flock 3.5 / Safari 5 (for Windows) returns 0
So just test that:
If the browser is Opera, you test for a number larger than 0 on scrollTop, and call scrollTop on only html, a la
var html = document.getElementsByTagName('html')[0];
var body = document.getElementsByTagName('body')[0];
$(html).animate({scrollTop:0+'px'},{'duration':1000,'easing':'swing'});
If the browser is Chrome, or Flock or Safari than scrollTop will return 0 and you test for that, acting accordingly:
$(html,body).animate({scrollTop:0+'px'},{'duration':1000,'easing':'swing'});
So, you'll set the effect on html for standards mode FF and IE (quirks should be covered, too. Ugh), and body for Chrome and Safari.
In Opera, which attempts to scroll both html and body, thus leading to mass freakishness, scrollTop returns a number greater than 0, so you call only html and you don't get the flickery nonsense.
So you can safely use both html and body when necessary, or just html when the browser is Opera.
And don't forget yer preventDefault() or that'll be another weird flicker you'll have to worry about. ;)
Hey, I'm no JS ninja, but I try hard and this works for me, and I don't have time right now to investigate it as much as I'd like, so I thought I'd post this here and help. If I'm wrong I'll hold up my hands and say it. ;) So feedback, please. :D
Tom.
Yep!
I had a problem with action of animate({scrollTop: }) function called in click() function.
The best way is http://www.zachstronaut.com/posts/2009/01/18/jquery-smooth-scroll-bugs.html#opera, which was written here by Divya Manian.
One need to use event.preventDefault() before calling scroll function or animate function to end click event before start scroll event.
Something like this:
$(<clicked_element>).click(function(event){
event.preventDefault();
$('html, body').animate({scrollTop: <value>}, 600);
});
EDIT: It's important to apply scroll method to $('html, body') elements
Related
Reference Link: http://old.crazyripples.com/?debug=1
So, I am using jQuery and the jQuery fullPage plugin. It helps me achieve frame by frame scrolling.
Now, for internal divs where the vertical height is greater than the window height I have used some functions where I simply check for the scrollbar position and stopPropagation to the plugin so that inner scrollbar scrolls without shifting the frame.
All works fine with chrome and since I built with chrome I used some calculations that I observed on chrome. But firefox is showing different results, especially with scrollTop.
I am aware of the fact that there can be a difference in height but if you see the logs in the reference link you will see, the height is almost the same(even if it isn't for you, its the scrollTop value that is an issue).
Here is the code that I am using to decide whether to stopPropagation or not.
$(document).on("keydown",function(e){
var story=$("#story"),
story_con=story.find(".container"),
story_top=story_con.scrollTop();
if(story.hasClass("active")){
// console.log(story_top,story_con.height(),story_con.innerHeight(),story_con.children("div").height(),story_con.children("div").innerHeight(),e.which);
console.log("Div ScrollTop: "+story_top, "Container Height: "+story_con.height(), "Container InnerHeeight: "+story_con.innerHeight(),"Conatiner Div Height: "+story_con.children("div").height());
//up arrow
if(story_top==0 && e.which==38){
console.log("prev frame")
}
//down arrow
//chrome 280+432 >= 676 i.e. 712>=676 true
//firefox 207+429 >= 676 i.e 636>=676 false
else if(story_top + story_con.height() >=story_con.children("div").height() && e.which==40){
console.log("next frame");
}
else{
story_con.focus();
console.log(story_con[0]);
console.log("stopped propagation");
e.stopImmediatePropagation();
}
return;
}
});
And this is how I am calling the plugin:
$('#main').fullpage({
sectionSelector:'.frame',
scrollingSpeed:800,
responsiveWidth:1025,
normalScrollElements: '#story, #startups, #services',
});
Replication:
Go to the reference link. Navigate to the second section(Our Story) by either scrolling, arrow keys or the menu. Now, only use arrow keys, the frame should scroll normally, but when the scroll completes, it should go to the next frame(does so in Chrome). See js logs for more details.
I would love it if anyone could help me in any way. I have been trying to debug this for sometime. Maybe I am focussing on the wrong issue? Any help will be appreciated.
P.S. I know the plugin offers a scrollOverflow option. That was inducing more issues than this approach.
Update: Since I wasn't able to find any solution so specific, I changed my approach of detecting if the frame scrollbar had reached its end. I used this:
//down arrow
else if(container[0].offsetHeight + container[0].scrollTop >= container[0].scrollHeight){
console.log("next frame");
}
*This is the start of my answer as I continue to debug to give you better details.
Currently using Firefox version 49.0.1 on window sizes smaller than 1280px your content inside your container classes are too tall.
Current proof:
In your divs, #story, #partners, and #services, if you where to give the div that is the direct child of div.container in each of the major sections a height: 200px all of your arrow down keypresses will work.
Edit 1
In magic.js line 111 is where your issue starts.
else if(story_top + story_con.height() >=story_con.children("div").height() && e.which==40){
The content within each of your containers, story_con.children("div").height(), is sometimes greater than story_top + story_con.height() so it does not go into the next page path that you desire.
Of course this all depends on the height of the window.
Your debug logging proving my point:
The Simple answer would be because Chrome and Firefox render pages differently. To understand why you get the differences in rendering have a look at this Explanation
I hope this clears it out.
Please check this example link: http://lab.cubiq.org/iscroll5/demos/probe/
If i run above example page in chrome and scroll through mousewheel, the page goes up by 100px every time. You can see there is Y position printed. If i run same above page in firefox 26.0 and scroll through mousewheel, the page goes up by 3px every time. You can see that page goes up very slow in firefox. Is there any way to fix them?
This is a problem with the iscrolljs library, as reported 8 days ago on the github site for iscroll. Please refer to: https://github.com/cubiq/iscroll/issues/577
If you debug the code on Firefox you will see that deltaY is being adjusted only by -3 each time a scroll event occurs. This is different to chrome which has a very large deltaY adjustment on scroll.
I would suggest waiting until a patch is supplied. If your need is urgent then I would recommend using the older version until a fix is available.
As I didn't have the option of reverting to an older version, I looked through the GitHub issue mentioned by Metalskin and I saw a temporary fix by a poster called 'justnorris'.
He modified the _wheel method in the iscroll-probe.js file directly at lines 1055 - 1057, with the following:
if ( 'deltaX' in e ) {
var multiply = ( e.deltaMode === 1 ) ? this.options.mouseWheelSpeed : 1;
wheelDeltaX = -e.deltaX * multiply;
wheelDeltaY = -e.deltaY * multiply;
}
Source: https://github.com/cubiq/iscroll/issues/577#issuecomment-33715370
Do a Ctrl+F5 (cache clear) of your page in Firefox and it should scroll fine now.
Note: This is a temporary working fix. Works for me as of today, on Firefox 27.0.1, Windows 8.
It seems body.scrollTop (and body.scrollLeft) are deprecated in ES5 strict-mode. What is the reason for this, given that it still seems okay to use these properties on other DOMElements?
Background Info:
I have a function that tries to increase (or decrease, as specified) the scrollTop values of all the ancestors of an element, till one of these actually changes. I am wondering if, to stay complaint with strict-mode, I should specifically check against the body element as the chain of parents moves upward.
[Obviously, bodyrefers to document.body]
It's Chrome's own incorrect behavior that is deprecated, and they're warning authors to stop relying on it.
The scrolling viewport is represented by document.documentElement (<html>) in standards mode or <body> in quirks mode. (Quirks mode emulates the document rendering of Navigator 4 and Explorer 5.)
Chrome uses body.scrollTop to represent the viewport's scroll position in both modes, which is wrong. It sounds like they want to fix this so they're encouraging authors to script for the standard behavior.
I don't think you need to change your code. There's nothing wrong with using body.scrollTop in standards mode so long as you understand it represents the scroll position of body only (typically 0, unless you've given body a scroll box).
You can see the warning by executing document.body.scrollTop in the console:
body.scrollTop is deprecated in strict mode. Please use documentElement.scrollTop if in strict mode and body.scrollTop only if in quirks mode.
I noticed my code stop working on newer versions of Chrome. I fixed it by using window.scrollY
Before:
var scrollTop = document.body.scrollTop;
Now:
var scrollTop = window.scrollY;
It works all the time now. You can find more documentation here.
Also, I was using:
document.body.scrollTop = 0;
now I replaced it with:
window.scrollTo(0, 0);
The following code works for me to set the popup in a correct position whenever the click event fires, for all browsers.
var scrollTop = window.scrollY; //For all browsers.
var scrollTop = document.body.scrollTop; //This works for only IE Edge specific versions
scrollTop refers to how much the element is scrolled. This means body shouldn't have a scrollTop because it is never scrolled, body has the topmost scrollbar so it's contents can be scrolled but not body itself.
The last picture on this page explains a lot:
https://developer.mozilla.org/en-US/docs/Web/API/Element.scrollTop
I've got a page with a header and a content.
The header has position: fixed; height: 200px, the content is below.
In the header I have a link <a href="#work" ...> . In the content there is a <div id="work">. When I click the link, the browser scrolls to the work div - the problem is half of the content is covered (remains underneath) the header, because it has position fixed!
I then used the jQuery anchorAnimate plugin, that uses jQuery animate. Here I slightly modified the plugin to take into account that 200px-offset. This worked out fine, in Chrome and Safari.
Not in Firefox, however. The plugin works ok, slides to the correct position, until it calls window.location.hash = element. Firefox then falls back to the default behaviour of setting the element at the top of the page (thus ignoring the offset due to the header - the first problem I described).
I know Firefox 3.6 implements an onhashchange listener. I overrode as per the documentation window.onhashchange = function(){}, which it does call, but it keeps on firing the default action of setting the elements at the top of the window, ignoring my header. How can I fix this?
(Otherwise, would it be possible to set somewhere a window offset in these "fixed header" cases?)
If you can't find a way to prevent Firefox's ohhashchange behavior, then your best best is to approach the problem in a different way. A couple of suggestions:
Modify anchorAnimate to never set window.location.hash (comment out line 34). The problem with that is that the url will never be changed, and users won't be able to bookmark or copy a url which directly points to that div.
Write your own code (or modify anchorAnimate) to do something like this:
var currentScroll = $('html, body').scrollTop();
window.location.hash = 'myAnchor';
$('html, body').scrollTop(currentScroll)
.animate({ scrollTop: destination - 200 });
That will set the anchor, but immediately scroll you back to where the browser was previously. From there you can animate to any desired scroll position.
I checked in Firefox (and am pretty sure for other browers) that the user will not see a flash of scroll changes.
I'm building an auto-follow div that is bound to the $(window).scroll() event. Here is my JavaScript.
var alert_top = 0;
var alert_margin_top = 0;
$(function() {
alert_top = $("#ActionBox").offset().top;
alert_margin_top = parseInt($("#ActionBox").css("margin-top"));
$(window).scroll(function () {
var scroll_top = $(window).scrollTop();
if(scroll_top > alert_top) {
$("#ActionBox").css("margin-top", ((scroll_top-alert_top)+(alert_margin_top*2))+"px");
console.log("Setting margin-top to "+$("#ActionBox").css("margin-top"));
} else {
$("#ActionBox").css("margin-top", alert_margin_top+"px");
};
});
});
This code assumes that there is this CSS rule in place
#ActionBox {
margin-top: 15px;
}
And it takes an element with the id "ActionBox" (in this case a div). The div is positioned in a left aligned menu that runs down the side, so it's starting offset is approximately 200 px). The goal is to start adding to the margin-top value once the user has scrolled past the point where the div might start to disappear off the top of the browser viewport (yes I know setting it to position: fixed would do the same thing, but then it would obscure the content below the ActionBox but still in the menu).
Now the console.log shows that the event is firing every time it should and it's setting the correct value. But in some pages of my web app the div isn't redrawn. This is especially odd because in other pages (in IE) the code works as expected (and it works every time in FF, Opera and WebKit). All pages evaluate (0 errors and 0 warnings according to the W3C validator and the FireFox HTMLTidy Validator), and no JS errors are thrown (according to the IE Developer Toolbar and Firebug). One other part to this mystery, if I unselect the #ActionBox margin-top rule in the HTML Style explorer in the IE Developer Tools then the div jumps immediately back in the newly adjusted place that it should have if the scroll event had triggered a redraw. Also if I force IE8 into Quirks Mode or compatibility mode then the even triggers an update.
One More thing, it works as expected in IE7 and IE 6 (thanks to the wonderful IETester for that)
I'm having a problem with your script in Firefox. When I scroll down, the script continues to add a margin to the page and I never reach the bottom of the page. This occurs because the ActionBox is still part of the page elements. I posted a demo here.
One solution would be to add a position: fixed to the CSS definition, but I see this won't work for you
Another solution would be to position the ActionBox absolutely (to the document body) and adjust the top.
Updated the code to fit with the solution found for others to benefit.
UPDATED:
CSS
#ActionBox {
position: relative;
float: right;
}
Script
var alert_top = 0;
var alert_margin_top = 0;
$(function() {
alert_top = $("#ActionBox").offset().top;
alert_margin_top = parseInt($("#ActionBox").css("margin-top"),10);
$(window).scroll(function () {
var scroll_top = $(window).scrollTop();
if (scroll_top > alert_top) {
$("#ActionBox").css("margin-top", ((scroll_top-alert_top)+(alert_margin_top*2)) + "px");
console.log("Setting margin-top to " + $("#ActionBox").css("margin-top"));
} else {
$("#ActionBox").css("margin-top", alert_margin_top+"px");
};
});
});
Also it is important to add a base (10 in this case) to your parseInt(), e.g.
parseInt($("#ActionBox").css("top"),10);
Try marginTop in place of margin-top, eg:
$("#ActionBox").css("marginTop", foo);
I found the answer!
I want to acknowledge the hard work of everyone in trying to find a better way to solve this problem, unfortunately because of a series of larger constraints I am unable to select them as the "answer" (I am voting them up because you deserve points for contributing).
The specific problem I was facing was a JavaScript onScoll event that was firing but a subsequent CSS update that wasn't causing IE8 (in standards mode) to redraw. Even stranger was the fact that in some pages it was redrawing while in others (with no obvious similarity) it wasn't. The solution in the end was to add the following CSS
#ActionBox {
position: relative;
float: right;
}
Here is an updated pastbin showing this (I added some more style to show how I am implementing this code). The IE "edit code" then "view output" bug fudgey talked about still occurs (but it seems to be a event binding issue unique to pastbin (and similar services)
I don't know why adding "float: right" allows IE8 to complete a redraw on an event that was already firing, but for some reason it does.
The correct format for IE8 is:
$("#ActionBox").css({ 'margin-top': '10px' });
with this work.
try this method
$("your id or class name").css({ 'margin-top': '18px' });