Force javascript to run *before* browser redraw (jsFiddle example) - javascript

I am building a little web based application using an HTML table. One unusual property of this table is that it has fixed top row and left column (similar to excel). I accomplished this using a little jQuery and CSS.
The problem is, the jQuery event that triggers my code is the $(window).scroll event, and evidently most browsers (Chrome and IE) redraw the page before the code that is called by this event is finished running. As a result, the left column and top row take a split second to "catch up" to the rest of the table.
I've provided a stripped down jsFiddle example in order to show you my problem. Note: The lag isn't very noticeable when the table is so small and (relatively speaking) empty of content. Nevertheless, it is there (assuming you aren't using firefox). Is there any way to get rid of this lag?
Thanks!

Just an idea, but maybe worth considering: You could try using requestAnimationFrame as described in this article (or in a similar way). That might smooth out the update/"lag" issues.

I didn't get this to work with either the scroll event or with requestAnimationFrame. What I ended up doing is attaching to the mousewheel event, which fires before scrolling and rendering has happend. If the scroll event is going downward, I can apply the appropriate class in time for rendering.

Related

Screen size/scroll events and Javascript/jQuery timing, updating page issue

I have a Javascript function called updatescreen() that performs various actions on page elements.
I call updatescreen() on page load, page scroll, touchmove, orientation and resize. Basically, any time the user is moving things around, I need to update elements to make the page look and function correctly.
Not every trigger actually modifies a page element, but I have to do some checking.
Everything works well, until I start scrolling (or flicking on an iPhone) very quickly. One trigger that happens is that I need to change the position of an element's "top" value (CSS). I have tried this with jQuery "animate" as well as just "css".
If I scroll slowly enough, everything is fine. If I scroll too fast, the script doesn't seem to keep up with my CSS/animation changes, and it ignores the last few, leaving the element in the wrong position. At least, this is what I think is happening.
Is it correct that firing different CSS values at the same element, too quickly, would cause the last ones to be ignored? Are there rules with regards to how jQuery handles this?
Any suggestions on how I could improve this entire workflow?
Thanks!

Javascript workaround for slow scrolling with smooth scrolling in firefox

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.

Browser stops responding to events during function execution, breaking "draggables"

I have a slider a little like this:
________
------------| |---------------------------------------
: <-- | slider | --> : : : :
------------|________|---------------------------------------
I'm using jQuery UI to make the slider draggable. This works fine.
The problem is that I'm executing a function each time the slider crosses a section boundary (indicated by :). This function takes approximately 30ms to execute (it's constructing a DocumentFragment and inserting it into the document). During this time the browser does not respond to events, so jQuery UI stops adjusting the slider's position and the drag is prematurely ended (the user is forced to release the mouse button and commence a new drag). This makes the slider feel jerky and buggy.
Is there a solution to this problem?
Edit: I've created a simple fiddle which demonstrates the problem. Note that while the drag is essentially paused during the execution of the slow function, it resumes afterwards. This makes me suspect that there's something about my more complex scenario which is causing the drag event to be cut short (perhaps the DOM manipulation is causing the position of the slider to change briefly).
Edit: After further investigation I'm much closer to understanding the problem. The DOM manipulation code contains a line something like $('.droppable').remove(). This removes the matching elements from the DOM after detaching any event handlers bound to them and removing any associated data. If I use .detach() instead, the behaviour is the same as in the simple fiddle above. Something untoward is happening during the cleanup.
I'd suggest to use jQuery's or Underscore's debounce function, or some equivalent method, to call the function just once every 100 or 200 ms or so.
This won't make things smooth, but at least they won't feel buggy.
Interesting article about it.

Hiding and showing div during page scroll on iphone

Need to display an element (div) ontop of webpage. During scroll the element should disappear and reappear after scroll ends.
To add to the complexity:
our code is a guest code (thus we cannot manipulate DOM structure etc).
our code is intended to work on iPhone/iPad (mobile Safari browser)
We've tried to listen to touchstart event on document / body and hide the element (div) in our dedicated handler. However, in some sites, (when DOM structure becomes reasonably complex) the scroll response time increases significantly, even if handler implementation is entirely empty.
We are looking for the proper way to manage the element (re)appearance with a minimal affect of the user experience while scrolling.
I would think Javascript is your best solution. You can dynamically insert your DIV to any content using document.createElement, then also add some javascript to listen for onScroll...
You could even populate the DIV using custom HTML built from the native code if you want.
Any help?
I don't know if you are a jQuery user, but this .scroll() function may help you do exactly what you want to do. Check out the demo to see how it works.
http://api.jquery.com/scroll/
In recent iOS version (5.x) fixed positioning (position:fixed in CSS) is fluently supported, so that your element will be positioned on screen coordinates. That might be a good starting point for solving your troubles.

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