- How the browser renders the document
- Receives the data (bytes) from the server.
- Parses and converts into tokens (<, TagName, Attribute, AttributeValue, >).
- Turns tokens into nodes.
- Turns nodes into the
DOM
tree. - Builds
CSSOM
tree from thecss rules
. CSSOM
andDOM
trees are combined into aRenderTree
.- Computes which elements are
visible
and theircomputed styles
. - Starting from the root of the dom tree.
Not visible
elements like (meta
,script
,link
) anddisplay: none
are ommited from the render tree.- For each
visible
node, find the appropriatematching CSSOM
rules
and apply them.
- Computes which elements are
- Reflow:
compute
the layout of eachvisible
element (position and size). - Repaint:
renders
thepixels
to screen.
- Repaint
- Occurs when changes affect the visibility.
- Triggers examples:
opacity
,color
,background-color
,visibility
.
- Reflow (Layout, LayoutFlush, LayoutThrashing)
- Occurs when the changes affect the layout.
- Triggers examples:
width
,position
,float
. - Recalculate of positions and dimensions.
- Has a bigger impact, changing a single element can affect all children, ancestors, and siblings or the whole document.
- Triggers (chagne dom or css, scrolling, user actions like
focus
). Reflow
only has acost
if the document has changed andinvalidated
thelayout
.Something Invalidates
+Something Triggers
=Costly Reflow
.
- Don't change styles by multiple statements, instead:
- Add
class
. - Change the
cssText
.
- Add
- Batch DOM changes
- Options to batch DOM changes
- Use a
documentFragment
to hold temp changes. - Clone, update, replace the node.
- Hide the element with
display: none
(1 reflow, 1 repaint), add 100 changes, restore the display (total 2 reflow, 2 repaint).
- Use a
- Options to batch DOM changes
- Don't ask for computed styles repeatedly, cache them into variable.
- Multiple reads/writes (like for the
height
property of an element)- Writes, then reads, from the DOM, multiple times causing document reflows.
- Read(
cached
), write(invalidate layout
), read(trigger layout
). - To fix: read everything first then write everything.
- Multiple reads/writes (like for the
- Resources
Chrome provide a really great tool that helps us to figure out what is going on with our code, how many reflows (layout) and repaint do we have and more details about the memory, events, etc.
Bad code with 6
costly reflows (layout):
var box1Height = document.getElementById('box1').clientHeight;
document.getElementById('box1').style.height = box1Height + 10 + 'px';
var box2Height = document.getElementById('box2').clientHeight;
document.getElementById('box2').style.height = box2Height + 10 + 'px';
var box3Height = document.getElementById('box3').clientHeight;
document.getElementById('box3').style.height = box3Height + 10 + 'px';
var box4Height = document.getElementById('box4').clientHeight;
document.getElementById('box4').style.height = box4Height + 10 + 'px';
var box5Height = document.getElementById('box5').clientHeight;
document.getElementById('box5').style.height = box5Height + 10 + 'px';
var box6Height = document.getElementById('box6').clientHeight;
document.getElementById('box6').style.height = box6Height + 10 + 'px';
Optimized to have 1
reflow:
var box1Height = document.getElementById('box1').clientHeight;
var box2Height = document.getElementById('box2').clientHeight;
var box3Height = document.getElementById('box3').clientHeight;
var box4Height = document.getElementById('box4').clientHeight;
var box5Height = document.getElementById('box5').clientHeight;
var box6Height = document.getElementById('box6').clientHeight;
document.getElementById('box1').style.height = box1Height + 10 + 'px';
document.getElementById('box2').style.height = box2Height + 10 + 'px';
document.getElementById('box3').style.height = box3Height + 10 + 'px';
document.getElementById('box4').style.height = box4Height + 10 + 'px';
document.getElementById('box5').style.height = box5Height + 10 + 'px';
document.getElementById('box6').style.height = box6Height + 10 + 'px';
- Optimize Selectors
- jQuery uses:
document.querySelectorAll()
.document.getElementById()
faster.- jQuery selector extensions.
- Avoid jQuery selector extensions (
:even
,:has
,:gt
,:eq
). - Avoid complex specificity.
- ID-Based Selectors the fastest.
- jQuery uses:
- Add
style
element for chaning > 20 instead of.css
. - Cache Length During Loops.
- Avoid inspecting large numbers of nodes
document.getElementById('id').getElementsByTagName('*')
better thandocument.getElementsByTagName('*')
.
- Cache DOM values in script variables
var sample = document.getElementById('test')