In the previous module, [some theory behind the critical rendering path](https://web.dev/learn/performance/understanding-the-critical-path) was
explored, and how render-blocking and parser-blocking resources can delay a
page's initial rendering. Now that you understand some of the theory behind
this, you're ready to learn some techniques for optimizing the critical
rendering path.

As a page loads, many resources are referenced within its HTML that provide a
page with its appearance and layout through CSS, as well as its interactivity
through JavaScript. In this module, a number of important concepts related to
these resources and how they affect a page's load time are covered.

## Render blocking

As was discussed in the [previous module](https://web.dev/learn/performance/understanding-the-critical-path), CSS is a [render-blocking](https://web.dev/articles/critical-rendering-path/render-blocking-css) resource,
as it blocks the browser from rendering any content until the [CSS Object Model
(CSSOM)](https://developer.mozilla.org/docs/Web/API/CSS_Object_Model) is constructed. The browser blocks rendering to prevent a [Flash of
Unstyled Content (FOUC)](https://en.wikipedia.org/wiki/Flash_of_unstyled_content), which is undesirable from a user experience standpoint.

In the preceding video, there is a brief FOUC where you can see the page without
any styling. Subsequently, all styles are applied once the page's CSS has
finished loading from the network, and the unstyled version of the page is
immediately replaced with the styled version.

Generally speaking, a FOUC is something you don't normally see, but the concept
is important to understand so that you know *why* the browser blocks rendering
of the page until CSS is downloaded and applied to the page. Render blocking
isn't necessarily undesirable, but you do want to minimize how long it lasts by
keeping your CSS optimized.

## Parser blocking

A [parser-blocking](https://web.dev/articles/critical-rendering-path/adding-interactivity-with-javascript) resource interrupts the HTML parser, such as a `<script>`
element without `async` or `defer` attributes. When the parser encounters a
`<script>` element, the browser needs to evaluate and execute the script before
proceeding with parsing the rest of the HTML. This is by design, as scripts may
modify or access the DOM during a time while it is still being constructed.

    <!-- This is a parser-blocking script: -->
    <script src="/script.js"></script>

When using external JavaScript files (without `async` or `defer`--- or
`type=module` which is `defer` by default), the parser is blocked from when the
file is discovered until it is downloaded, parsed, and executed. When using
inline JavaScript, the parser is similarly blocked until the inline script is
parsed and executed.

> [!NOTE]
> **Note:** A parser-blocking `<script>` must also wait for any in-flight render-blocking CSS resources to arrive and be parsed before the browser can execute it. This is also by design, as a script may access styles declared in the render-blocking style sheet (for example, by using `element.getComputedStyle()`).

## The preload scanner

The [preload scanner](https://web.dev/articles/preload-scanner) is a browser optimization in the form of a secondary HTML
parser that scans the raw HTML response to find and speculatively fetch
resources before the primary HTML parser would otherwise discover them. For
example, the preload scanner would allow the browser to start downloading a
resource specified in an `<img>` element, even when the HTML parser is blocked
while fetching and processing resources such as CSS and JavaScript.

To take advantage of the preload scanner, critical resources should be included
in HTML markup sent by the server. The following resource loading patterns are
not discoverable by the preload scanner:

- Images loaded by CSS using the `background-image` property. These image references are in CSS, and can't be discovered by the preload scanner.
- Dynamically-loaded scripts in the form of `<script>` element markup injected into the DOM using JavaScript or modules loaded using [dynamic `import()`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Operators/import).
- HTML rendered on the client using JavaScript. Such markup is contained within strings in JavaScript resources, and isn't discoverable by the preload scanner.
- CSS `@import` declarations.

These resource loading patterns are all late-discovered resources, and therefore
don't benefit from the preload scanner. Avoid them whenever possible. If
avoiding such patterns *isn't* possible, however, you may be able to use a
`preload` hint to avoid resource discovery delays.

> [!NOTE]
> **Note:** The `preload` resource hint is covered in the [next module on resource
> hints](https://web.dev/learn/performance/resource-hints).

## CSS

CSS determines the presentation and layout of a page. As described earlier, CSS
is a render-blocking resource, so optimizing your CSS could have a considerable
impact on overall page load time.

### Minification

[Minifying CSS](https://web.dev/articles/minify-css) files reduces the file size of a CSS resource, making them
quicker to download. This is accomplished primarily by removing content from a
source CSS file such as spaces and other invisible characters, and outputting
the result to a newly optimized file:

    /* Unminified CSS: */

    /* Heading 1 */
    h1 {
      font-size: 2em;
      color: #000000;
    }

    /* Heading 2 */
    h2 {
      font-size: 1.5em;
      color: #000000;
    }

    /* Minified CSS: */
    h1,h2{color:#000}h1{font-size:2em}h2{font-size:1.5em}

> [!NOTE]
> **Note:** Some advanced CSS minifiers may employ additional optimizations, such as coalescing redundant rules into multiple selectors. However, such advanced CSS optimizations can be risky, and may not work or scale well with all CSS approaches or design systems.

In its most basic form, CSS minification is an effective optimization that could
improve your website's FCP, and perhaps even LCP in some cases. Tools such as
[bundlers](https://bundlers.tooling.report/) can automatically perform this optimization for you in production
builds.

### Remove unused CSS

Before rendering any content, the browser needs to download and parse all
style sheets. The time required to complete parsing also includes styles that
are unused on the current page. If you are using a bundler that combines all CSS
resources into a single file, your users are likely downloading more CSS than
needed to render the current page.

To discover unused CSS for the current page, use the [Coverage tool](https://developer.chrome.com/docs/devtools/css/reference/#coverage) in Chrome
DevTools.
![A screenshot of the coverage tool in Chrome DevTools. A CSS file is selected in its bottom pane, showing a considerable amount of CSS unused by the current page layout.](https://web.dev/static/learn/performance/optimize-resource-loading/image/fig-1.png) The coverage tool in Chrome DevTools is useful for detecting CSS (and JavaScript) unused by the current page. It can be used to split CSS files into multiple resources to be loaded by different pages, as opposed to shipping a much larger CSS bundle that can delay rendering of the page.

Removing [unused CSS](https://developer.chrome.com/en/docs/lighthouse/performance/unused-css-rules/) has a two-fold effect: in addition to reducing download
time, you're optimizing [render tree](https://web.dev/articles/critical-rendering-path/render-tree-construction) construction, as the browser needs to
process fewer CSS rules.

> [!IMPORTANT]
> **Important:** Depending on the architecture of your website, it may not be possible to completely eliminate unused CSS---nor should you expect to. Focus on big wins: if you see a large part of a CSS file that is unused by the current page, it may either be used by a different page (which you can move to a different file altogether), or be deleted entirely if the CSS is no longer being used in your project.

### Avoid CSS `@import` declarations

While it may seem convenient, you should avoid `@import` declarations in CSS:

    /* Don't do this: */
    @import url('style.css');

Similarly to how the `<link>` element works in HTML, the `@import` declaration
in CSS lets you import an external CSS resource from within a style sheet. The
major difference between these two approaches is that the HTML `<link>` element
is part of the HTML response, and therefore discovered much sooner than a CSS
file downloaded by an `@import` declaration.

The reason for this is that in order for an `@import` declaration to be
discovered, the CSS file that contains it must *first* be downloaded. This
results in what is known as a *request chain* which---in the case of CSS---delays
how long it takes for a page to initially render. Another drawback is that
style sheets loaded using an `@import` declaration can't be discovered by the
preload scanner, and therefore become late-discovered render-blocking resources.

    <!-- Do this instead: -->
    <link rel="stylesheet" href="style.css">

In most cases, you can replace the `@import` by using a
`<link rel="stylesheet">` element. `<link>` elements allow style sheets to be
downloaded *concurrently* and reduces overall load time, as opposed to `@import`
declarations, which downloads style sheets *consecutively*.

> [!NOTE]
> **Note:** If you need to use `@import`---such as for [cascade
> layers](https://developer.mozilla.org/docs/Learn/CSS/Building_blocks/Cascade_layers) or third-party style sheets---you can mitigate the delay by using the `preload` directive for the imported style sheet. Additionally, CSS preprocessors---such as SASS or LESS---commonly use the `@import` syntax as part of a developer experience improvement that allows for separate and more modularized source files. However, when a CSS preprocessor encounters `@import` declarations, the referenced files are bundled and written into a single style sheet, avoiding the consecutive request penalty that `@import` causes in plain CSS.

### Inline critical CSS

The time it takes to download CSS files can increase a page's FCP. Inlining
critical styles in the document `<head>` eliminates the network request for a
CSS resource, and---when done correctly---can improve initial load times when a
user's browser cache is not primed. The remaining CSS can be loaded
[asynchronously](https://www.filamentgroup.com/lab/load-css-simpler/), or appended at the end of the `<body>` element.

> [!IMPORTANT]
> **Key term:** Critical CSS refers to the styles required to render content that is visible within the initial viewport. The initial viewport concept is sometimes referred to as "above the fold". The remaining content on a page is left unstyled while the remaining CSS is loaded asynchronously.

    <head>
      <title>Page Title</title>
      <!-- ... -->
      <style>h1,h2{color:#000}h1{font-size:2em}h2{font-size:1.5em}</style>
    </head>
    <body>
      <!-- Other page markup... -->
      <link rel="stylesheet" href="non-critical.css">
    </body>

> [!IMPORTANT]
> **Important:** Extracting and maintaining critical styles can be difficult. Which styles should be included? Which viewport(s) should be targeted? Can the process be automated? What happens if a user scrolls down before the non-critical CSS has loaded? How are users affected if they experience a FOUC? These are all good questions that should be considered, as your website's architecture may make using critical CSS prohibitively difficult. However, the performance benefits can be worth the effort in some select cases, so investigate whether critical CSS is a viable option for your website!

On the downside, inlining a large amount of CSS adds more bytes to the initial
HTML response. Because HTML resources often can't be cached for very long---or at
all---this means that the inlined CSS is not cached for subsequent pages that may
use the same CSS in external style sheets. Test and measure your page's
performance to make sure the trade-offs are worth the effort.

### CSS demos

<iframe allow="camera; clipboard-read; clipboard-write; encrypted-media; geolocation; microphone; midi" loading="lazy" src="https://chrome.dev/f/learn_performance_css/?attributionHidden=true&amp;sidebarCollapsed=true&amp;previewSize=100" style="height: 100%; width: 100%; border: 0;" title="Learn Performance CSS demo"></iframe>

## JavaScript

JavaScript drives most of the interactivity on the web, but it comes at a cost.
Shipping too much JavaScript can make your web page slow to respond during page
load, and may even cause responsiveness issues that slow down interactions---both
of which can be frustrating for users.

### Render-blocking JavaScript

When loading `<script>` elements without the `defer` or `async` attributes, the
browser blocks parsing and rendering until the script is downloaded, parsed, and
executed. Similarly, inline scripts block the parser until the script is parsed
and executed.

### `async` versus `defer`

`async` and `defer` allow external scripts to load without blocking the HTML
parser while scripts (including inline scripts) with `type="module"` are
deferred automatically. However, `async` and `defer` have some differences that
are important to understand.
![A depiction of various script loading mechanisms, all detailing the parser, fetch, and execution roles based on various attributes used such as async, defer, type='module' and a combination of all three.](https://web.dev/static/learn/performance/optimize-resource-loading/image/fig-2.svg) Sourced from <https://html.spec.whatwg.org/multipage/scripting.html>

Scripts loaded with `async` are parsed and executed immediately once downloaded,
while scripts loaded with `defer` are executed when HTML document parsing is
finished---this occurs at the same time as the browser's `DOMContentLoaded` event.
Additionally, `async` scripts may execute out-of-order, while `defer` scripts
are executed in the order in which they appear in the markup.

> [!IMPORTANT]
> **Note:** Scripts loaded using the `type="module"` attribute are deferred by default, while scripts loaded by injecting `<script>` markup into the DOM with JavaScript behave like `async` scripts.

### Client-side rendering

Generally, you should avoid using JavaScript to render any critical content or a
page's [LCP element](https://web.dev/articles/lcp#what-elements-are-considered). This is known as client-side rendering, and is a technique
used extensively in Single Page Applications (SPAs).

Markup rendered by JavaScript sidesteps the preload scanner, as the resources
contained within the client-rendered markup [are not discoverable](https://web.dev/articles/preload-scanner#rendering_markup_with_client-side_javascript) by it. This
could delay the download of crucial resources, such as an LCP image. The browser
only begins downloading the LCP image after the script has executed, and added
the element to the DOM. In turn, the script can only be executed after it has
been discovered, downloaded, and parsed. This is known as a [critical request
chain](https://developer.chrome.com/en/docs/lighthouse/performance/critical-request-chains/) and should be avoided.

Additionally, rendering markup using JavaScript is more likely to generate
[long tasks](https://web.dev/articles/long-tasks-devtools) than markup downloaded from the server in response to a navigation
request. Extensive use of [client-side rendering of HTML can negatively affect
interaction latency](https://web.dev/articles/client-side-rendering-of-html-and-interactivity). This is especially true in cases where [a page's DOM is
very large](https://web.dev/articles/dom-size-and-interactivity), which triggers significant rendering work when JavaScript modifies
the DOM.

### Minification

Similar to CSS, [minifying JavaScript](https://developer.chrome.com/en/docs/lighthouse/performance/unminified-javascript/) reduces a script resource's file size.
This can lead to quicker downloads, allowing the browser to move onto the
process of parsing and compiling JavaScript more quickly.

Additionally, minification of JavaScript goes one step further than minifying
other assets, such as CSS. When JavaScript is minified, it isn't only stripped
of things such as spaces, tabs, and comments, but symbols in the source
JavaScript are shortened. This process is sometimes known as *uglification*. To
see the difference, take the following JavaScript source code:

    // Unuglified JavaScript source code:
    export function injectScript () {
      const scriptElement = document.createElement('script');
      scriptElement.src = '/js/scripts.js';
      scriptElement.type = 'module';

      document.body.appendChild(scriptElement);
    }

When the preceding JavaScript source code is uglified, the result may look
something like the following code snippet:

    // Uglified JavaScript production code:
    export function injectScript(){const t=document.createElement("script");t.src="/js/scripts.js",t.type="module",document.body.appendChild(t)}

In the preceding snippet, you can see that the human readable variable
`scriptElement` in the source is shortened to `t`. When applied across a large
collection of scripts, the savings can be quite significant, without affecting
the features a web site's production JavaScript provides.

If you're using a bundler to process your web site's source code, uglification
is often done automatically for production builds. Uglifiers---such as [Terser](https://terser.org/),
for example---are also highly configurable, which lets you tweak the
aggressiveness of the uglification algorithm to achieve maximum savings.
However, the defaults for any uglification tool are usually sufficient to strike
the right balance between output size and preservation of capabilities.

### JavaScript demos

<iframe allow="camera; clipboard-read; clipboard-write; encrypted-media; geolocation; microphone; midi" loading="lazy" src="https:/chrome.dev/f/learn_performance_javascript/?attributionHidden=true&amp;sidebarCollapsed=true&amp;previewSize=100" style="height: 100%; width: 100%; border: 0;" title="Learn Performance Javascript demo"></iframe>

## Test your knowledge


What is the best way to load multiple CSS files in the browser?
The CSS `@import` declaration. Try again. Multiple `<link>` elements. Correct!
What does the browser preload scanner do?
It is a secondary HTML parser that examines raw markup to discover resources before the DOM parser can in order to discover them sooner. Correct! Detects `<link rel="preload">` elements in an HTML resource. Try again.
Why does the browser temporarily block parsing of HTML by default when
downloading JavaScript resources?
To prevent a Flash of Unstyled Content (FOUC). Try again. Because evaluating JavaScript is a very CPU-intensive task, and pausing HTML parsing gives more bandwidth to the CPU to finish loading scripts. Try again. Because scripts can modify or otherwise access the DOM. Correct!

## Up next: Assisting the browser with resource hints

Now that you have a handle on how resources loaded in the `<head>` element can
affect initial page load and various metrics, it's time to move on. In the next
module, [resource hints](https://web.dev/learn/performance/resource-hints) are explored, and how they can give valuable hints to
the browser to begin loading resources and opening connections to cross-origin
servers sooner than the browser otherwise would without them.