Rendering glitch in Chrome - javascript

I've created a menu that moves to the current window position by scrolling. When I scroll up and down right after, sometimes a glitch appears on Chrome 30 with OS X 10.9 and Windows 7. After hovering, the anchor tag jumps to the right position (1 pixel up). Is there anything wrong with my code? Is this a known bug?
Check this JSFiddle Demo!
$(document).ready(function(){
$(window).scroll(function(){
var newTop = ($(window).scrollTop() + 40) +'px';
$('#menu').stop().animate({ top: newTop}, 500);
});
});
Edit: It's fixed in Chrome 31.

I'm fairly certain this is a rendering bug since:
Manually triggering a repaint causes the glitch to go away.
The glitch doesn't occur in other browsers I tested.
Fortunately, triggering a repaint is a fairly straight-forward workaround, albeit an annoying one:
I added a callback to the animation:
$('#menu').stop().animate({ top: newTop }, 500, function(){
$('#menu').css('overflow', 'hidden');
setTimeout(function(){
$('#menu').css('overflow', 'auto');
}, 10);
});
jsFiddle Demo
Unfortunately, it seems both the setting and unsetting of some property (here I chose overflow) was necessary. The 10 is a little sketchy, but when you're working around a browser rendering bug, I'm not sure you can do much better.
Best of luck!

I agree with Adam, this is definitely a rendering bug. If you animate the menu using the translate() transform-function instead, it does not happen.
There are other bonuses to using this method as well: http://www.paulirish.com/2012/why-moving-elements-with-translate-is-better-than-posabs-topleft/
jQuery core does not allow you to animate using translate() out of the box, but there is a plugin that enables this at http://ricostacruz.com/jquery.transit/ , or you can opt for using .css() and let css transitions do the heavy lifting.
Here is an example using the plugin:
var menu = $("#menu");
$(window).scroll(function(){
var newTop = $(window).scrollTop();
menu.stop().transit({ y: newTop +'px' }, 500);
});
Plugin demo at http://jsfiddle.net/Hb3jS/5/
Here is an example using CSS transitions:
js
var menu = $("#menu");
$(window).scroll(function(){
var newTop = $(window).scrollTop();
menu.css({ transform: 'translateY(' + newTop +'px)' });
});
css
#menu {
transition: all .5s;
}
CSS demo at http://jsfiddle.net/Hb3jS/6/

Related

Don't block scrolling animation when setting scroll programmatically via jQuery

Here's a full codepen of the situation I will describe in detail below: https://codepen.io/Adam0410/full/MGXjaz/
The javascript contained in the codepen (the core of the issue) is below:
var collapsed = false;
$(window).scroll(function(){
var scroll = window.pageYOffset || document.documentElement.scrollTop;
if (scroll > 207 && !collapsed) {
$("#header").css({
position: "fixed",
height: "50px",
"line-height": "50px"
});
$("#content").css("margin-top", "207px");
$(document).scrollTop(scroll - 50);
collapsed = true;
} else if (scroll < 155 && collapsed) {
$("#header").css({
position: "static",
height: "257px",
"line-height": "257px"
});
$("#content").css("margin-top", "0");
$(document).scrollTop(scroll + 50);
collapsed = false;
}
});
I am attempting to make a large header that is part of the flow of the document, that then turns into a smaller fixed header as you scroll down past it. I want the action of the user scrolling to be smooth during this process.
If you view the pen on mobile (or use chrome's device toolbar) with smooth scrolling and scroll slowly around the breakpoint where the header changes you can see it's completely smooth.
However if you view it on a desktop (with chrome again, or any other browser) the scrolling with a scroll wheel is done in 100-pixel increments. For this reason once again if you scroll around the breakpoint where the header changes you can see it is not smooth.
This occurs since the 100-pixel scrolling doesn't occur instantly and in the process of changing the scrollTop of the document the 100-pixel scrolling animation gets canceled. Is there any way to detect and resume this scrolling animation once I've set the scrollTop property?
Please check https://codepen.io/anon/pen/PeabEL
Changed the js to
$(window).scroll(function(){
var scroll = window.pageYOffset || document.documentElement.scrollTop;
var newHeight = 50;
if(257-scroll>50)
newHeight = 257-scroll;
$("#header").css({
position: "fixed",
height: newHeight+"px",
"line-height": newHeight+"px",
});
});
also added
#content {
...
margin-top:257px;
}
and,
#header {
...
position: fixed;
}
I have another approach with the help of a very small plugin called smoothwheel (Get it here). I extended the answer of #Rohith Murali and created an example. Have a look here:
https://codepen.io/anon/pen/NMBdpx
The plugin itself enables you to scroll smoothly with low impact on performance. Does this fit your needs?

Scrolling is jittery in IE, Safari, OSX

I'm trying to do some basic parallax animation, but the movement is extremely jittery as soon as I test in IE or any OSX browser - not sure why!
http://willmurdoch.com/scrolltest/
$(window).scroll(function(){
$('.hero').each(function(){
if($(this).offset().top - $(window).scrollTop() > -$(window).height() && $(this).offset().top - $(window).scrollTop() < $(window).height()){
var myTranslate = Math.ceil($(window).scrollTop() - $(this).offset().top);
$(this).find('.heroSlides').css('-webkit-transform', 'translateY('+myTranslate/2+'px)');
$(this).find('.scrollWrap').css('-webkit-transform', 'translateY('+myTranslate/5+'px)');
}
});
});
I've tried locking scroll functions to only fire every 100ms and transition in between, adding hardware acceleration to every animated element, but nothing seems to do it! Any help would be appreciated!
One of the things that I've found that adds smoothness to my CSS transformations, is to add the CSS Transformations
https://www.w3schools.com/css/css3_transitions.asp
Another thing you can do is look at skrollr and how that project works. It does math based easing for its smooth scrolling.
EDIT
On the page you posted, try changing the following functions:
$(window).scroll(function(){
scrollLogic();
console.log($(window).scrollTop());
closeNav();
});
change to:
$(window).scroll(function(){
//scrollLogic();
console.log($(window).scrollTop());
closeNav();
});
var scrollInterval = setInterval(function() {
scrollLogic();
}, 1000/30);
Then change the myTranslate part of scrollLogic. Play with different values to make the change more/less gradual.

Page noscroll keeping scrollTop position in sticky footer layout

I can't handle such a mind-breaker:
It's common approach to hide page scroll when a tall popup shows. But when you set overflow: hidden to html and body elements, the content automatically returns to it's top (scrollTop: 0). It's no problem to keep scrollTop position, and reset it on popup's disappearing. But if you use transparent mask, user will see unnecessary jump from current scroll position to the top. How to escape this?
In the current Chrome and Firefox, I can set overflow: hidden only to html element to reach what I want, but it's not working on mobile devices.
Maybe someone can propose a good cross-browser solution.
I don't think this should be happening. I would look at the popup code to see if it's the culprit sending the page to the top and using subpar css to position the popup element.
In any case, here's code that ought to counter the behavior you're encountering. Since I cannot reproduce the problem, I cannot test my proposed fix. I think you'll find though that your pop up will be scrolled away out of view.
function keepScroll(){
var x = $('body').scrollLeft() + $(document.documentElement).scrollLeft();
var y = $('body').scrollTop() + $(document.documentElement).scrollTop();
$('html').css({
'overflow':'hidden'
});
$('body').css({
'overflow':'hidden'
});
$(window).scrollTop(y).scrollLeft(x);
}
The sicky footer layout has html and body height equal to '100%'. And when you set overflow:hidden it crops all the content and returns it to the top position.
To avoid this, you should set html and body height to 'auto' if scroll exists (you should check it to keep sticky footer behavior)
function keepScroll(){
var scrollHeight = $('body')[0].scrollHeight > $('html')[0].scrollHeight ? $('body')[0].scrollHeight : $('html')[0].scrollHeight,
keepCSS = scrollHeight > $(window).height() ? {'overflow':'hidden','height':'auto'} : {'overflow':'hidden'};
$('html, body').css(keepCSS);
}
See the fiddle, for live demo
Edit 1
This solution is still not working on mobile (overflow: hidden doesn't disable scrolling on iPad, the position 'fixed' fix for body throw the content to the top), so the issue is open
Edit 2
Find a fix, for mobiles. Maybe it isn't so clean, but works.
var scrollKeeper = (function() {
var scrollHeight = $('body')[0].scrollHeight > $('html')[0].scrollHeight ? $('body')[0].scrollHeight : $('html')[0].scrollHeight,
keepCSS = scrollHeight > $(window).height() ? {'overflow':'hidden','height':'auto'} : {'overflow':'hidden'},
scrollTop = 0;
return {
keep : function() {
scrollTop = $(window).scrollTop();
$('body').css({'position': 'fixed', 'width':'100%', 'top': -scrollTop + 'px'});
$('html, body').css(keepCSS);
},
release : function() {
$('html, body').removeAttr('style').scrollTop(scrollTop);
}
}
})();
Tip: Of course in the real development you should use css classes to avoid removeAttr(style) etc.
Tested on iPhone and Ipad (iOS 8+).
The fiddle http://jsfiddle.net/m1eav032/5/

CSS Zoom interfering with jQuery scrollTop

I'm creating a Website that, on Mobile Browsers, zooms out, as it's a fixed width website. Instead of using the viewport meta tags I've taken to the following:
html, body {
zoom: 0.8;
}
This works great, but the problem is with my jQuery. I'm using simple jQuery code for a one-page website smooth scrolling, shown below:
/* Start Navigation */
jQuery('nav ul.menu li').click(function(e) {
if(!scrollingAnim) {
var page = jQuery(this).attr('data-page');
updateMenu(page);
scrollingAnim = true;
jQuery('html, body').stop().animate({
scrollTop: (jQuery(page).offset().top - 70)
}, 2000, 'swing', function() {
scrollingAnim = false;
});
}
e.preventDefault();
return false;
});
/* End Navigation */
This used to work fine, but for obvious reasons will not work with my zoom. I've tried multiplying it by the zoom level, but it doesn't work. Is there anything you'd suggest?
jQuery's .offset().top is changing with the change of the window scroll when you have CSS zoom involved...
Take a look at my answer here https://stackoverflow.com/a/21048208/1090395
Hope it helps
Faced with similar problem related to zoom and offset().Top. Tried to play with values in JS console and found this formula:
var scrollTopAnimateTo = ($(anchor).offset().top - $(".header").height()) * zoom + $(window).scrollTop() * (1 - zoom);
where zoom < 1.

using a simple jquery script to have a div follow the page on scroll

I'm trying to use this script here: http://css-tricks.com/scrollfollow-sidebar/ to make a simple div that follows the window as the user scrolls. I changed it from 0 to topPadding and changed topPadding to topPadding*2 to get the right top offset.
Unfortunately this has the side effect of the object making the page a little longer and allowing the user to scroll infinitely. This bug is also actually in the original code without my larger toppadding changes if you make the window small enough.
I also tried another plugin for jquery, but it didn't work at all and this gives me what I need, so how can I fix it?
Why not just use CSS.
#theNonMovingDiv {position:absolute; position: fixed; top: Npx; right:Mpx}
position:fixed; doesn't work in ie6, but including the position:absolute; will give you a rough approximation.
I've knocked together this quick amendment, which limits based on the document height. I'm not certain that jQuery is giving an accurate height, hence a safety barrier of 100px. Even if the height isn't quite right, any extra scrolling will be limited and certainly not infinite.
<script type="text/javascript">
var documentHeight = 0;
var topPadding = 15;
$(function() {
var offset = $("#sidebar").offset();
documentHeight = $(document).height();
$(window).scroll(function() {
var sideBarHeight = $("#sidebar").height();
if ($(window).scrollTop() > offset.top) {
var newPosition = ($(window).scrollTop() - offset.top) + topPadding;
var maxPosition = documentHeight - (sideBarHeight + 100);
if (newPosition > maxPosition) {
newPosition = maxPosition;
}
$("#sidebar").stop().animate({
marginTop: newPosition
});
} else {
$("#sidebar").stop().animate({
marginTop: 0
});
};
});
});
</script>
I can duplicate your bug in my browser (Firefox 3.5).
The problem is that the code doesn't look to see if the bottom of the sidebar falls off the end of the document.
Your best bet is to use the .height() method to check. You can get the height of the sidebar (as presented in the example) as $("#sidebar").height(), and the height of the whole document as $(document).height().
What exactly the behavior should be -- up to you. It involves an extra if, to make sure all your pixels line up right, but design questions, like how the sidebar should align against the bottom, are going to be a matter of personal taste.

Categories

Resources