Reducing the Cost of a Reflow
So what does this mean for semantics and a mobile app? On the Web, semantic HTML is critical to a website being searchable by search engines like Google, as well as accessible to those using screen readers. HTML5 brings with it a whole host of new tags like <article> and <section> that help make the markup even more semantic and helps avoid the dreaded <div> soup that often plagued designs of any sort of complexity. However we’re finding that semantics is often needing to take a backseat to making efficient use of our HTML. For example, to generate a tableview-like structure, we use an unordered list. Instead of wrapping the content of each list item in an <a> tag, we simply listen for user interaction directly on the <li> node and remove the <a> all together. (Truth be told, we’re finding that a lot of our <a> tags are extraneous.) We’ve also started applying some basic styling to the <html> tag to avoid wrapping the entire body in a <div> when our content needs a wrapper (we figured the <html> tag was already there–might as well use it for something). Finally, we haven’t been using the new tags offered with HTML5 (like <section> or <article>) very often simply because <div> is shorter.
What we’re working toward here is developing our apps so they spend less time in reflow. We’ve found that it is likely the reflow time that causes mobile web apps to “feel slow.” First, we need to shorten the time it takes to perform a reflow. We take care of this by removing extraneous tags: removing <a> tags when we can just listen for tap events on an <img> or <li>, cutting down on <div> wrappers, etc. Next, we need to limit the number of times a reflow is required. A reflow is triggered whenever the DOM is changed or the dimensions of an element change–this could be adding/removing an element or text, or changing the margins or font size of an element.
Reducing the Number of Reflows
The developer tools provided with the desktop version of Safari provide a great way to determine how changes to a page affect the need for a reflow/repaint. While it doesn’t give any sort of indication how long a reflow/repaint would take on a mobile device, using the timeline tab in the developer tools in Safari does give a good indication of how many reflows would be required (since Mobile Safari renders pages similarly to the desktop version). Unfortunately, we have yet to find a suitable tool for watching Mobile Safari’s processes.
var node = document.getElementById('some_element'); node.style.border = '2px solid #0F0'; node.style.margin = '5px'; node.style.height = '30px';
This “simple” style adjustment triggered three reflow/repaints of the page. On a desktop a reflow probably takes less than 15ms so it’s not a big deal. However, on a mobile device, a reflow can easily seem to take over 500ms which means that three reflows triggered in rapid succession could easily take a mobile device well over a second to finish processing. To avoid this, use classes to modify an element’s style whenever possible. Style changes applied because of a change in classes only triggers one reflow. Alternatively, use the cssText property to affect all the styles at once (again, only triggering one reflow):
node.style.cssText = 'border:2px solid #0F0;margin:5px;height:30px';
Beyond changing the dimensions of an element, there are times when you may need to make a lot of changes to the DOM (perhaps when drastically updating a view). Unfortunately, every modification made to the DOM requires a reflow/repaint. Below shows the reflow/repaint cost of replacing the header on Float’s mobile site with the word “hi” wrapped in a <div>:
To avoid a significant number of reflows being triggered, we need a way to modify the DOM without triggering reflows. The way to do that is to clone a node in the DOM, make changes to the clone, and then swap the old node with the new node.
var node = document.getElementById('some_element'), new_node = node.cloneNode(true); // We want this to be a deep clone // Apply changes to the cloned node var a = document.createElement('span'), var b = document.createTextNode('some content'); a.appendChild(b); new_node.innerHTML = ''; // Empty all the children out of the node new_node.appendChild(a); // Out with the old, in with the new node.parentNode.replaceChild(new_node, node);
We also tested what the cost would be if we first hid the header (display:none), made the changes, and then made it visible again (display:block). A hidden element doesn’t affect the layout of the page, so it shouldn’t trigger a repaint/reflow, right? Well, sorta. Below is the results of hiding the header, making the changes, and then making it visible again.
Seems like while an element is hidden, Safari still recalculates style (although doesn’t attempt a reflow until we set display back to block). This seems to be an improvement over simply making changes directly to the DOM, but we’re going to opt for the clone, modify, and swap method.
Last month, we looked at using template files to help keep a project organized, but they are also very helpful toward performance optimization as well. Because the markup of a template is determined before being added to the DOM, it only triggers one reflow when adding an entire new view–making it rather inexpensive to manage a layout using templates. We used Safari to determine the cost of switching back and forth between two views from this demo from that post:
Despite the DOM of the page changing dramatically when I select a tweet and then click back, it only causes two reflows to occur.
We see a lot of comments that the mobile web browser needs a lot of work before its ready to handle complicated apps, and while that’s true, Web development skills also need to be improved. The mobile device is simply not as lenient as a desktop device. Let’s not forget, these devices have a fraction of the processing power, memory and bandwidth as a their PC counterparts. Every aspect of the mobile design and development process must be reexamined for efficiences and places where you can improve your skills and know-how in order to provide better end products for your users.
Where are you finding need for improvement in your own Web development skills that you never realized before going mobile?
If you know you need to build a mobile Web app, but you need some consulting help, feel free to contact us.
Latest posts by Daniel Pfeiffer (see all)
- A More Mobile-Friendly Captivate HTML Template - October 21, 2013
- 3 Tools To Help You Optimize Your PhoneGap App’s Performance - October 15, 2013
- Tin Can iOS Library Compatible With Version 1.0 - May 2, 2013