Javascript workaround for slow scrolling with smooth scrolling in firefox - javascript

I am a developer for a web application. In this application there is a certain scenario where there are multiple position:fixed elements, and canvases and a overflow:scroll element. In this scenario, scrolling is super slow on firefox when smooth scrolling is enabled.
From the user's perspective the solution is simply to disable smooth scrolling. However, as a developer I can't ensure that the user has done this.
Is there anywhere that I can tell firefox to not to use smooth scrolling for my website from javascript (or html)? Or is there any other known workaround for this?

I do understand that your question basically is how to disable smooth scrolling. however I will answer you a little differently to get this working.
Why different?
Even if you can detect smooth scrolling of users, you cannot force the user to disable it. In other words, you are trying to cover the problem instead of solving it. so lets solve it!
Intro: pixels-to-screen pipeline
On each frame the browser does the following steps to render the page on screen.
JavaScript. Typically JavaScript is used to handle work that will result in visual changes, whether it’s jQuery’s animate function, sorting a data set, or adding DOM elements to the page. It doesn’t have to be JavaScript that triggers a visual change, though: CSS Animations, Transitions, and the Web Animations API are also commonly used.
Style calculations. This is the process of figuring out which CSS rules apply to which elements based on matching selectors, e.g. .headline or .nav > .nav__item. From there, once rules are known, they are applied and the final styles for each element are calculated.
Layout. Once the browser knows which rules apply to an element it can begin to calculate how much space it takes up and where it is on screen. The web’s layout model means that one element can affect others, e.g. the width of the element typically affects its children’s widths and so on all the way up and down the tree, so the process can be quite involved for the browser.
Paint. Painting is the process of filling in pixels. It involves drawing out text, colors, images, borders, and shadows, essentially every visual part of the elements. The drawing is typically done onto multiple surfaces, often called layers.
Compositing. Since the parts of the page were drawn into potentially multiple layers they need to be drawn to the screen in the correct order so that the page renders correctly. This is especially important for elements that overlap another, since a mistake could result in one element appearing over the top of another incorrectly.
details and source: https://developers.google.com/web/fundamentals/performance/rendering/?hl=en
Step 1:
First step is to remove render costly css properties. You might not be able to remove alot, however you can replace rgba(255,255,255,1); with #fff which removes the alpha layer.
check this for more details: https://csstriggers.com/
some properties do not need to do a layout or a paint and there are less heavy than others.
Step 2:
Check for forced synchronous layout triggers. These happen when you force the browser to do a layout while its in the javascript step, then return to javascript, instead of walking smoothly along the pipeline on each frame. to do this, avoid getting layout attributes and setting them directly afterwards in a loop for example.
here is a list of what causes sync layout: https://gist.github.com/paulirish/5d52fb081b3570c81e3a
read more: https://developers.google.com/web/tools/chrome-devtools/profile/rendering-tools/forced-synchronous-layouts?hl=en
Step 3:
Move components on the page that need to be repainted regularly into new layers.
The browser needs to repaint every time you scroll or an animation is playing. to avoid a full page repaint and only repaint the part that is changing, move that part (ex parallax, navigation, animation) to a new layer on the browser (think about it like photoshop layers)
to do so use the will-change css property to tell the browser to move it to a new layer, and use transform: translateZ(0); if you want to force the broswer to move it.

Have you tried adding
backface-visibility: hidden;
to you fixed position elements?
I would rather fix the source of the problem. Often there is one small detail that creates a giant bottleneck and that is easy to fix with the change of one line of code or something. Note that you most probably won't need to reduce the "good looks" of the app at all; it's just a matter of avoiding the small but devastating-for-performance details of the browser's layout engine.
I'll make a guess and say that something on you web app is causing very large repaints and/or frequent reflows. Check for things like usage of offsetTop and position: fixed. Also using requestAnimationFrame instead of updating for every scroll event is something worth looking at. Here's a good guide on both finding and fixing scrolling performance problems.

Use inspect element to try and get a handle on the specific cause.
Also, if you've not installed FireBug, install it and use it instead of the default inspect element. This will give you more code details and allow you to step through the script to find the problem.
There also plugins for FireBug for various frameworks, which can aid the diagnostics if your using one of those frameworks.
We can make assumptions about the cause or come up with shotgun solutions; but, only you can diagnose your code to find the specifics.

Related

In Chrome, SVG elements constructed too far off-screen do not render when brought into view

I am creating a web-site that drives content for a large 2D area off a CMS, so I have a system that runs on a timer, examines the part of the area that is currently on-screen, and loads content that is close enough to the view area that it might soon come into view.
This all seems to work quite nicely, apart from one small glitch.
Some of my content is SVG elements created procedurally via JS (the load mechanism feeds data from the CMS into JS functions, which create the using document.createElementNS and insert it into a div in the correct absolute position).
This content appears fine if is on-screen at the time it is loaded (this happens when the page is initially loaded).
And it also appears if it loaded while an animation is moving the visible area (animation is used to follow paths across the 2D space).
HOWEVER, if I am manually moving the visible area (which I have implemented via click+drag) then the SVG elements are added to the document tree, but when they come into view they do not render.
If I do something to "nudge" the renderer, such as hiding an unrelated element via DevTools, or resizing the window slightly, then they appear.
I am thinking this may be a bug in Chrome? e.g. where it has initially decided the elements need not be drawn and does not reprocess correctly when that needs reconsideration? Or maybe I am missing something, I am only semi-experienced in manipulating HTML documents via JS (but after a quick look I do not see the same behaviour in firefox...)
I am moving the visible area by changing the (left, top) of a parent element (I do not want to use scrolling for that as the size of the 2D space is not defined in advance...)
Otherwise, is there some way I could trick the browser into recalculating what should be drawn? I was wondering about having a small transparent element on screen that I show and hide on a timer, although a workaround that prevents the problem in the first place would be preferable...
Thanks for any advice!
Ian
p.s. I cannot instantly produce demo code for this as the code-base is moderately large, but I will spend time to make a simpler example if that proves necessary...

CSS performance - how to evaluate - animation (transition) of floating button size on scroll (transform scale vs height/width)

Introductory information:
I've made a fixed menu button to show the navigation menu when using a mobile device. For this application I'm using the Headroom.js script to make the button smaller when scrolling downwards to ensure that it doesn't block too much of the content. The animation/transition is applied by adding a class with the given changes.
In the original method i changed the size and look of the button by changing height/width of the parent element and padding of the child element with CSS (and css transition).
The new method, which I've read could/should be better according to various sites, is changing the size of the button by using transform: scale(). Note that i'm also moving the element a bit by also applying translate3d(20px,20px,0) in this method. However, it feels a bit smoother when scrolling using the transform: scale() method (could be a placebo effect though), but using chrome dev tools' timeline gives me seemingly inconclusive results.
Therefore a part of my question is also how I should evaluate the best method. Is timeline in Chrome Dev tools the best option, or is there a better way to do it? And which elements of the timeline should I base my choices on? and the other thing is, based on your interpretation of the images and/or tests combined with your knowledge, which method performs the best (or should perform the best in theory)?
Beneath you can see two examples of the timeline with each method.
Changing height/width and padding (original method):
Method using transform: scale() to change the size:
Also you can try the different methods in fiddles here:
link: Original method changing height/width and padding
link to new method: using transform:scale
Please ignore the poor layout of everything; especially the button. The ugly image inside the menu button is just to show, that there's an image included in the layout on my own page and to take that into performance considerations. The images in the back is also included since it's a webshop with a lot of images which could influence performance.
CSS for added class that makes the changes in the original method:
.mobile-nav.headroom--unpinned {
height: 40px;
width: 40px;
}
.headroom--unpinned .mobile-content{
padding-top:4px;
}
CSS for the added class using transform:scale():
.mobile-nav.headroom--unpinned {
transform:scale(.5) translate3d(20px,20px,0);
}
So to summarize my questions:
How do I evaluate which methods has the best performance, and which method would you say performs the best?
A final note: I know that the methods are different (animating different things and more elements in the original method) but these are the 2 options which i prefer as it is right now.
I believe you are missing the point, Chris: the reason why no other property but transform and opacity should ever be animated is because they don't trigger a repaint in anything else, even if the element is in the document flow (and because you can basically do anything with these two alone in like 95% of the cases).
From the "hit-on-performance" point of view, there are two types of animations:
those that trigger a repaint in other elements than the animated element
those that do not.
That's the main reason behind recommending animations by transform, opacity or position:relative;left|right|top|left. Because they don't actually move the element in flow, thus not triggering a repaint to every single other element in flow after the one being animated.
Now, if the said parent was positioned absolute (which I assume to be the case), it wouldn't have triggered a repaint to the rest of DOM anyway so the differences between that method and transform would have been minor. Inconclusive, as you put it. In theory, repainting two elements instead of one should be slower.
If you need to test, make 10k clones and trigger animation on all of them, with each method.
That will be conclusive.
If you really want to min-max this (as in spend absurd amounts of time on hardly noticeable improvements, as I do) you will find plenty of resources that will recommend:
replacing any .animate() with .velocity()
never animating anything but transform or opacity, although Velocity claims they animate anything without a hit on performance (i find that debatable/arguable, at best) - but it's a net improvement over .animate()
sticking to CSS transitions, if possible (basically if you don't need chains)
using Web Animations API
Personal advice: never count on synced CSS animations, especially when you have many of them. If you change tabs or the system does something extremely resource heavy for a while, your animations will be way off. If you need chains, chain.

Best JavaScript library for animating multiple divs

I have a grid of div boxes that I will be animating. They will be moving across the screen after a user drags one of the boxes (to re-align into a grid).
Currently I am using JQuery to change the css left and top positions of all of the divs and running this on an interval.
It is laggy if there are more than 50 boxes. How do I make this less laggy? Is there an animation library that is better for this, or do I just need to limit it to 50 boxes?
Image of layout:
You have a few options to optimize the performance.
Newer browsers have requestAnimationFrame that lets the browser take care of the animation timing in order to optimize Javascript animations. Rather than using times to perform the animation, which is what jQuery framework uses, you repeatedly a callback to requestAnimationFrame. The browser will call your function with a progress variable for the animation, and you render the current stage of your animation based on the progress variable. requestAnimationFrame for smarting animating talks about this in depth. Google Closure is the only framework I am aware of that uses requestAnimationFrame however, and it's rather heavyweight.
CSS animations. jQuery offers CSS animation, so do many other frameworks. CSS animations give you hardware acceleration, so the animation is much faster. Unfortunately, CSS animations are relatively new and not yet well supported, so you'll probably end up falling back to Javascript animation on older browsers, depending on the library you use.
Optimize your Javascript. Instead of animation each and every box in the grid, encapsulate each row in a div and animate the entire div instead. That should speed the animation up by a bit. I'm sure there are other ways you can optimize based on your current implementation.
Honestly, I don't know of any library that will make this work more efficiently for you, though there are many libraries out there that are faster than jQuery. The issue isn't just the jQuery, its the fact that you have 50 elements that are all moving/draggable, thus requiring a lot of the browser's resources.
If you can post your code there may be a few things that we could suggest to speed it up slightly.
The two biggest things problems that I can think of are if you added those boxes programmatically and added the handler for each as you added the element to the page, and if you don't store your selectors in variables. Aside from that I would have to see the code.
Have a look at:
jQuery isotope
It has options to allow you to use css3 animations if available or use jQuery / JS animations.
Handy for grid like animation and arrangements.
Some brave soul has managed to add drag and drop to isotope too. http://tyler-designs.com/masonry-ui/ (a bit clunky but works)
There are several ways of increasing the performance. One would be to reduce the amount of DOM elements required for each box. Another is to not animate (and render) boxes outside of the current viewport. Give all boxes that are outside of the viewable area "display: none;" and exclude them before starting a new animation. If you want to go even further you can start to recycle boxes instead of showing and hiding them when the user is scrolling through the page.
This way you will always get the same performance no matter how many boxes you have (above the amount that you can fit in the viewport).
This technique is called UI virtualization. There are several projects that use it like: http://github.com/mleibman/SlickGrid/wiki. It's really useful when you need to render a lot of elements (hundreds, thousands, millions). But it takes quite some work to get it right. And I don't know about any generic working components that are easy to plug in. I tried to find an article that explains it. This is the only thing I could come up with for now, it's for Silverlight though: http://www.silverlightshow.net/items/Virtualization-in-Silverlight-4-RC.aspx
Also try this this plugin for jQuery. Use the regular 'animate' method and it will try to use (hardware accelerated) CSS animations where possible: http://playground.benbarnett.net/jquery-animate-enhanced/

Blur all the objects(Images,div,text..) that comes behind a div tag

Need your help.
I created a static semi-opaque banner which stays at the top of a website. When a user scrolls the website the entire container objects goes underneath the banner. I want all the objects (images, text..etc) getting blury effect as it goes underneath the banner.
Thanks
The only way you're going to be able to do this is by getting fancy with some CSS and javascript. CSS doesn't support blur directly, but you can emulate it with text-shadow. Images can also be blurred with a little jquery/css/javascript magic, but will be problematic because you can't partially blur an image (what happens when only part of the image is under the banner?). It could probably be done by layering your images and keeping track of their position on screen, but all of this seems like a lot of work for a very small return.
So, assuming you've decided to give all of this a shot, you're going to have to use javascript to determine which parts of the page have passed under the banner and apply the style to those parts. The difficulty of this task will scale with the complexity of your page layout. In a best case scenario, your banner and content container are both 100% the width of the html body. At this point, it would be fairly trivial to write some kind of scanner that traverses the dom every time you page scroll to find elements that the blur should be applied to. However, best-case-scenario is rarely the case at hand, at which point I'd recommend abandoning the effort to pursue something with a greater ROI.
This isn't possible with CSS nor jQuery. You might be able to do something with IE's filters, however that's IE only (of course), and will invalidate your CSS.
Currently, there is no way to do this, although something might come along in CSS 4 or something.
The Chrome nightly builds support some filters, however there isn't an alpha blur filter (yet, at least).

What actions and events cause a browser to repaint its entire viewport?

I'm trying to implement the wmd-editor from the google code repository (like the one used on stackoverflow right here) and I'm running into an issue.
As you type into the textarea, it kicks off two paint operations in the browser. One to repaint the textarea itself, and one to repaint the preview panel. You can watch this happening on stackoverflow by opening the chrome inspector and using the timeline tab while typing some text into a question field.
But on my page, the browser repaints the entire viewport when it has to do these paint operations. And that takes much longer... about 100ms for each paint operation on my page versus about 1ms on stackoverflow.
In my testing this seems to be css related... I can recreate this behavior in the wmd-new example page by stripping all styles.
My page isn't public yet, but hopefully I can ask in a generic way... what will cause the browser to repaint the entire viewport on a dom change instead of just repainting that portion of the dom?
A view of what I'm talking about here.
AHA! Ah-effing-ha! (forgive the enthusiasm)
The issue is that I was using the box-shadow css property to frame my page. It takes longer to reflow/repaint content when the browser needs to calculate that shadow on each change (~100ms vs ~1ms). And when using wmd-editor, you're updating the dom on each keypress, so that difference adds up. And the effect is most exaggerated when the browser is maximized, as it recalculates the entire viewport.
So maybe that's one of the reasons stackoverflow doesn't have any frames or shadows on the page... just clean edges.
You can see what I mean at this example page. Open it up in firefox, maximized the page, and start typing away. Now use firebug to remove the box-shadow property on the body element, close firebug back up and try again. Big difference.
Thanks to Balpha for his comment, which was spot on.
Check this presentation, around slide 70 and the next ones. They explain a bit what can cause reflow and repaint.
http://www.slideshare.net/nzakas/high-performance-javascript-webdirections-usa-2010
Without the specific code / CSS is hard to answer but I can say something general like, if the fragment DOM that was changed influences other elements in the page :)
Also note that in stackoverflow WMD, when you enter a newline it also causes a whole viewport repaint. So maybe it has something to do with your WYSIWYG area not having width and height well defined? I'm guessing that if you give them width and height they won't affect other elements in the page

Categories