I'm working on a site using css3 animations, it works perfectly in Safari and Firefox, but for some reason performance in Chrome is awful. (around 15 fps)
http://triple-tested.com/animations/
The animations are quite simple, basically a few large circles layered up. I've also added a few png sprite animations using javascript.
I know about hardware acceleration but I don't think that is the problem, it seems to be some quirk that is unique to Chrome. The css animations perform 'OK' alone but once I add the sprites performance drops considerably.
$.fn.spriteme = function(options) {
var settings = $.extend({ framerate: 30 }, options);
return this.each(function(){
var $el = $(this),
curframe = 0,
width = settings.width,
fr = 1000/settings.framerate;
(function animloop(){
if(curframe == settings.frames) { curframe = 0; }
$el.css('background-position', (curframe*width)*-1 + 'px center');
curframe++;
setTimeout( animloop, fr );
})();
});
};
This is the code I've wrote to animate my sprites, but as I said it performs perfect in Safari and Firefox so I don't think it's the problem. Chrome seems to have an issue with animating using css alongside sprites.
I've tried everything I can find online but if anyone has any suggestions please let me know.
I'm using the latest stable chrome on mac btw (17.0.963.93)
You can see the css (using less) here btw
http://triple-tested.com/animations/css/style.less
Thanks for the replies guys, I think it is an issue with certain versions of chrome as it works perfect in the latest canary builds.
I ended up stripping back some of the animations for chrome, falls back gracefully to static images.
Related
I am losing my mind with this seemingly simple code.
I have created a sticky menu for a few sites and they all share the same problem. On iOS devices, at least the iPhone 6 with up to date iOS, the menu jumps into its fixed position too early. It's as if iOS miscalculates the offset for the element and runs the function too early. Though for the life of me I can't figure out how or why. On desktop it works fine. On Android it works fine. Please help!! The site is [DreaD Illustrations][1]. I have tried everything I can think of and find on the internet. Also, I noticed, it calculates incorrectly on initial load, but when you scroll down and scroll back up it seems to work. Help! The code is below.
var navBar = jQuery("nav.site-navigation.main-navigation.primary.mobile-navigation");
var topofNav = navBar.offset().top;
stickyDiv = "being-sticky";
mahMain = jQuery('#main').outerWidth();
jQuery(window).load(function(){
jQuery(window).on('scroll', function() {
if (jQuery(document).scrollTop() > topofNav) {
navBar.addClass(stickyDiv);
navBar.outerWidth(mahMain);
} else {
navBar.removeClass(stickyDiv);
}
});
});
.being-sticky {
position:fixed;
top:0;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
Thanks everyone for your help!
So it was a simple fix for me for safari. I created a variable of whenToScroll and set it differently if it was safari or another browser! That seemed to fix it! Though I tried the safari setting for chrome and no go.
if (jQuery.browser.safari)
var whenToScroll = jQuery("div.hgroup.full-container").outerHeight();
else
var whenToScroll = navBar.offset().top;
Have you tried setting a timeout and seeing how that displays on IOS? If it's a timing thing that's being read differently, you can use navigator.userAgent to remove the class a bit later for IOS devices only.
if(/iPhone|iPad|iPod/.test(navigator.userAgent)) { //IOS browsers
setTimeout(function(){
navBar.removeClass(stickyDiv);
}, 7000); // however many milliseconds you need it to wait for
}else{
navBar.removeClass(stickyDiv);
}
I have added smooth scrolling to a site of mine using this piece of JavaScript when clicking on hash links.
$('a[href*=#]')
.click(onAnchorClick);
function onAnchorClick(event)
{
return ! scrollTo(this.hash);
}
function scrollTo(target)
{
var e = $(target);
var y = e.exists() ? e.offset().top : 0;
if(y == 0 && target != '#top')
return false;
if(Math.max($('html').scrollTop(), $('body').scrollTop()) != y)
$('html,body')
.animate({scrollTop: y}, 500, function() { location.hash = target; } );
else
location.hash = target;
return true;
}
$.fn.exists = function()
{
return this.length > 0 ? this : false;
}
Works fantastic in desktop browsers and looks to work fine on at least iOS devices as well. However, on my WinPhone 8 device it was garbage. Scrolling was a mess and didn't even end up where it should. So I decided to not enable it there through an if( ! /Windows Phone 8\.0/.test(navigator.userAgent)).
Now it works well, and seems the browser on the WinPhone actually is smooth scrolling by default, which is great.
But it is of course a bit dumb to have a smooth scroll script active if the browser already does this by default. Is there a way I can detect if a browser already has a smooth scrolling feature enabled?
I managed to solve it this way:
<style>
body {
scroll-behavior: smooth;
}
</style>
<script>
if(getComputedStyle(document.body).scrollBehavior === 'smooth'){
console.log('This browser supports scrollBehavior smooth');
}
</script>
Yes and no. Unfortunately there are no standards for these types of things. However there are work arounds, one of which you are already doing: browser sniffing.
Basically, that's about as advanced as this kind of detection goes because some browsers don't yet even support smooth scrolling officially or without experimental developments (like Chromium). And standards won't be set unless the majority are on the same page. Not only that but it also comes down to GPU hardware abilities as some devices and computers struggle with smooth scrolling and animations. So technically speaking, even if a browser did support smooth scrolling, who's to say the device or desktop running it can render fast enough to even display the effect. That's another bottle neck.
I believe someday in the future there will be more of a need for browser feature specifications such as this to better improve user interactions, but until that day you're doing it right.
Several years later, there now is a CSS property in the Working Draft for this:
scroll-behavior 🎉
So instead of the Javascript in my original question, or similar, we can just do this:
html {
scroll-behavior: smooth;
}
#media (prefers-reduced-motion: reduce) {
html {
scroll-behavior: auto;
}
}
Right now, it seems to work for all browsers except IE and Edge, and since this is just a nice-to-have feature that makes things look a bit nicer... Yeah, I don't really care about IE or Edge. 😛👍
If we make a simple test case like:
document.documentElement.addEventListener('scroll', function() {
console.log(document.documentElement.scrollTop);
});
And then go and scroll using the scrollbar by clicking the track, or by using PageDown/PageUp, then we can see that we only get one event at the end of the scrolling animation.
Now theoretically I could fix some of that behaviour by simulating the scroll events. Example code with jQuery and Underscore:
$(function () {
var $document = $(document), until = 0;
var throttleScroll = _.throttle(function () {
$document.scroll();
if (+new Date < until) {
setTimeout(throttleScroll, 50);
}
}, 50);
$document.keydown(function (evt) {
if (evt.which === 33 || evt.which === 34) {
until = +new Date + 300;
throttleScroll();
}
});
});
But it still does not work. We only get scroll events with the original scrollTop and the destination scrollTop, no values in between.
If then go and console.log(document.documentElement.scrollTop) every 10ms, then we can see that IE just does not update the scrollTop as it scrolls.
This is very frustrating if we want to "pin" something to the scroll position. It gets jerky with IE.
I did not observe this behaviour on any other browser, and did not test with previous IE versions.
If anyone has found a way to fix IE's behaviour (maybe there's a magic CSS to turn off smooth scrolling in IE 11?) then I would very much like to hear about it!
Thanks :-)
You said: "If anyone has found a way to fix IE's behaviour (maybe there's a magic CSS to turn off smooth scrolling in IE 11?) then I would very much like to hear about it!"
This does not turn it off, but here is what I use to resolve the smooth scroll issue in ie with Fixed elements.
if(navigator.userAgent.match(/Trident\/7\./)) {
$('body').on("mousewheel", function ( event ) {
event.preventDefault();
var wd = event.wheelDelta;
var csp = window.pageYOffset;
window.scrollTo(0, csp - wd);
});
}
The issue you're describing is limited to instances of Internet Explorer 11 running on Windows 7. This problem doesn't affect the platform upon which IE 11 was born, Windows 8.1. It seems as though IE 11 on Windows 7 falls into a similar category as other scrolling implementations mentioned above. It's not ideal, but it's something we have to work with/around for the time being.
I'm going to continue looking into this; in fact, just dug a Windows 7 machine out of the closet to setup first thing in the morning so as to investigate further. While we cannot address this head-on, perhaps, maybe, there's a way we can circumvent the problem itself.
To be continued.
As a crazy last resort (seems not so crazy actually if the issue is critical) - maybe turn off native scrolling completely and use custom scrolling (i.e. http://jscrollpane.kelvinluck.com/)? And bind onscroll stuff to its custom events: http://jscrollpane.kelvinluck.com/events.html
Looks like there's a post on IE and forcing a screen "paint" to help with drag-drop. Seems the opposite of most performance efforts but might work? https://stackoverflow.com/a/12395506/906526 (code from https://stackoverflow.com/users/315083/george)
function cleanDisplay() {
var c = document.createElement('div');
c.innerHTML = 'x';
c.style.visibility = 'hidden';
c.style.height = '1px';
document.body.insertBefore(c, document.body.firstChild);
window.setTimeout(function() {document.body.removeChild(c)}, 1);
}
You might try CSS animations so the browser handles animation/ transition. Eg applying a show/ hide class on scroll and, CSS animation.
.hide-remove {
-webkit-animation: bounceIn 2.5s;
animation: bounceIn 2.5s;
}
.hide-add {
-webkit-animation: flipOutX 2.5s;
animation: flipOutX 2.5s;
display: block !important;
}
If not having a browser handle animation (with creative css), keyframes and JS performance might offer leads. As a plus, I've seen several sites with navigation bars that "reappear" after scroll end.
I recently found the perfect mini-script for the pictures section of the site I've been working on non-stop for the last half year. I had it working but apparently in Firefox it doesn't want to play nice. What's even odder is I've played with it a bit; all my references are fine, but the thing won't do what I say anymore. Another oddity is I searched Google for some of the code, found it again (to examine it), and wouldn't you know: that incarnation runs perfectly on WebKit and even ran flawlessly on Firefox! I am about to pull my hair out, so, any help is appreciated. By the way, the script in question gets dynamically loaded towards the end of the DIV. My site (pictures section): http://www.elemovements.com/pictures and the replica: http://www.gmcbryde.com/. Here is the code, as well, just for good measure (which you can find unminified at http://el.x10.mx/js/logic/pictures.js [you need only concern yourself with the first 40-50 lines or so]):
if ( $('div.highslide-gallery').length ) {
$( function() {
var $Div = $('div.highslide-gallery'),
$Ul = $('ul.horiz-list'),
$UlPadding = 0;
$Ul.width(9000);
$Div.width( $Div.parent().parent().width() - 26 );
var $DivWidth = $Div.width();
$Div.css( {overflow: 'hidden'} );
var lastLi = $Ul.find('li:last-child');
$Div.mousemove(function(e){
var $UlWidth = lastLi[0].offsetLeft + lastLi.outerWidth() + $UlPadding;
var left = (e.pageX - $Div.offset().left) * ($UlWidth-$DivWidth) / $DivWidth;
$Div.scrollLeft(left);
} );
} );
}
The issue I am experiencing is that the DIV just won't move in Firefox. In WebKit, it works as expected but all that happens in good ol' Mozilla is the mousemove() event gets fired. I appreciate anyone's help. Thank you.
I just remembered that Firefox requires an initial width for elements, and I had forgotten to again include the CSS I had for it after I first scrapped it. That made all the difference. Thanks anyway!
I have the following function that ties into a bunch of different plugin settings, allowing you to configure the handles, speed, and angles for rotating objects. Everything runs crystal clear and really nice in IE9, but firefox is jerky.
// 1. FUNCTION ROTATE ANIMATIONS IN
function rotate_on(degree, index){
clearTimeout(rotateofftimer); /* CLEAR ANIMATION OUT TIMER */
// A. APPLY THE CROSS-BROWSER CSS FOR ROTATIONS
if((ievers==6)||(ievers==7)||(ievers==8)){ if(ievers==8){ /* IE 8 CODE */ current_obj.css({/* IE8 */'-ms-filter':'"progid:DXImageTransform.Microsoft.BasicImage(rotation='+degree+')"',/* IE<8 */'filter':'progid:DXImageTransform.Microsoft.BasicImage(rotation='+degree+')'});} else { /* IE 6/7 CODE */ };
} else { /* NON IE */
current_obj.css({/* W3C CSS3 standard */'transform':'translateX(0)rotate('+degree+'deg)','transform-origin':OS.rotate_handle_on_set[index],/* Firefox */'-moz-transform':'translateX(0)rotate('+degree+'deg)','-moz-transform-origin':OS.rotate_handle_on_set[index],/* Chrome, Safari, Mobile, Etc. */'-webkit-transform':'translateX(0)rotate('+degree+'deg)','-webkit-transform-origin':OS.rotate_handle_on_set[index],/* Opera */'-o-transform':'translateX(0)rotate('+degree+'deg)','-o-transform-origin':OS.rotate_handle_on_set[index],/* IE>=9 */'-ms-transform':'rotate('+degree+'deg)','-ms-transform':'translateX(0)rotate('+degree+'deg)','-ms-transform-origin':OS.rotate_handle_on_set[index]});};
// B. TEST FOR REPEAT ROTATIONS - IF VALUES ARE THE SAME, REPEAT ROTATIONS
if(OS.rotate_on_set[index]==OS.rotate_off_set[index]){
// SAVE THE ENDING VALUE TO PICKUP ON NEXT PLAY (IF LOOPING)
OS.rotate_on_set[index]=degree;OS.rotate_off_set[index]=degree; degree++;
}else{ if(degree<OS.rotate_off_set[index]){ degree++ };};
// C. TRIGGER THE FUNCTION IN A TIMER, BASED ON USER SPEED
rotateontimer = setTimeout(function(){rotate_on(degree, index)},OS.rotate_speed_on_set[index]);};
The strange thing is, when I turn the speed down so that the animation is really slow, it's basically jerking through 1 frame at a time in Firefox, but IE9 seems to know how to translate that into a smooth/slow animation. Could it be something to do with the timers?
Thanks!
This just seems to be the way Firefox is. I have the same problem of choppy JS animations and ONLY when viewed with Firefox. Internet Explorer 9 (in standard mode plus compatibility modes "IE7" and "IE8") and Chrome both display smooth animations under all circumstances.
Trust me, we're not the only ones with this problem and to day no clear solution exists.