As mentioned in my previous post, there are several concepts we can utilize now to help improve performance. Specific JS and CSS implementations aside, the basic performance gains you can achieve have to do with these specific ideas:
- Reduce resource byte size (HTML, CSS, JavaScript, Images, Fonts, etc…)
- Initiallity serve the minimum amount of critical resources necesssary to render the page
- Proper caching
Critical Rendering Path
In order to improve performance we must understand the sequence of tasks our browser performs to paint pixels on the screen.
Why so “critical”?
The Critical Rendering Path
is the path the browser takes to render a page.
The critical
characteristics of it have to do with the required resources it takes to get there.
The path looks like this:
- Download site HTML, begin parsing, and start downloading required resources (CSS, JavaScript, etc…)
- Construct DOM tree from the HTML (Document Object Model)
- Construct CSSOM tree from the CSS (CSS Object Model)
- Evaluate JavaScript
- Combine the DOM and the CSSOM into the render tree
- Layout the various elements (Boxes) on the page (Geometry)
- Paint the pixels to the screen
- Composite the layers to the screen
When a user interacts with the site the browser will continually do something like steps 4-8 at 60fps (frames per second). This means your JavaScript and CSS animations should do their thing in less than 16ms (1 second / 60 = 16.66ms) to paint the frame. Since the browser has some housekeeping work to do, we really only have about 10-12ms for this to feel “silky smooth”.
For more info, check out this great write-up by Paul Lewis on the Critical Rendering Path.
Render Blocking
You may have heard the term Render Blocking
thrown around. When the browser loads the HTML from top down,
it will encounter render blocking resources that are critical to rendering the page.
When the browser encounters a Render Blocking
resource like CSS it will continue parsing the DOM, download subsequent resources, css, images, fonts, etc…
However, the page will not render until each blocking resource has been resolved and evaluated by the browser.
CSS is Render Blocking
because if we were able to render the HTML without CSS then there would be no styling and the site would appear plain.
Having small and efficient CSS is important because it will block the rest of the site from rendering until it’s been downloaded and parsed.
JavaScript is a little more complicated to explain. It is considered Parser Blocking
and not so much Render Blocking
.
Since JavaScript can manipulate the DOM and styling, it’s important for the browser, when it encounters a <script>
tag,
to stop and check to see if there are any changes to the DOM or styling before proceeding forward.
This StackOverflow answer sums up the difference between Render Blocking
and Parser Blocking
really well for us.
Fonts using @fontface are Render Blocking
which should make sense since they’re loaded via CSS.
Images are not Render Blocking
and is why you may see content and interact with the page while images are still loading.
The lower number of render blocking resources we serve the more efficient our critical rendering path becomes and the faster things will render.
It’s our job to minimize the number of and the byte size of critical resources the site requires to render.
Optimizations
There are several ways to optimize the Critical Rendering Path:
- Load less DOM nodes
- Asynchronously load JavaScript with the
async
ordefer
attributes - Try not to block the parser by manipulating DOM and styles with Javascript during page load
- Reduce network calls by inlining critical CSS and JavaScript for “above the fold” content and defer all other resources
- Asynchronously load fonts
- Place Media Queries into separate files and only load them when the media type matches
We’ll look at some of these in the next post!
Thanks for reading,
-Andrew Del Prete