---
title: Defer render-blocking CSS and JavaScript
description: >-
  Defer non-critical JavaScript with `async` or `defer` and non-critical CSS
  with the async pattern, while keeping CSS for content visible in the initial
  viewport render-blocking to prevent flash of unstyled content.
source_url:
  html: >-
    https://shopify.dev/docs/storefronts/themes/best-practices/performance/defer-non-critical-resources
  md: >-
    https://shopify.dev/docs/storefronts/themes/best-practices/performance/defer-non-critical-resources.md
api_name: liquid
---

# Defer render-blocking CSS and Java​Script

Be strategic about render-blocking resources. Defer non-critical JavaScript using `async` or `defer`, and defer non-critical CSS using the async pattern. Keep CSS for content visible in the initial viewport render-blocking to prevent flash of unstyled content.

***

## Why

When the browser parses HTML and encounters a standard `<link rel="stylesheet">` or a synchronous `<script src="">`, it must pause parsing the HTML, download and process the resource, then resume parsing. This delay directly affects how quickly [First Contentful Paint (FCP)](https://web.dev/fcp/) can occur.

CSS blocks rendering to prevent Flash of Unstyled Content (FOUC), where HTML renders with default browser styles instead of custom styles, and to prevent layout shifts from late-arriving styles. Critical CSS for content visible in the initial viewport should remain render-blocking. Chrome DevTools might flag render-blocking resources, but that doesn't mean you should eliminate all of them. Critical CSS should block rendering. Evaluate each resource individually.

***

## How

### CSS

Keep critical CSS for content visible in the initial viewport render-blocking, and make non-critical styles non-blocking. Use [`section.index`](https://shopify.dev/docs/api/liquid/objects/section#section-index) to conditionally apply the async CSS pattern to section styles outside the initial viewport, because the first sections render above the fold and their styles are critical.

```liquid
{%- if section.index > 2 -%}
  <link rel="stylesheet" href="{{ 'section-styles.css' | asset_url }}" media="print" onload="this.media='all'">
  <noscript><link rel="stylesheet" href="{{ 'section-styles.css' | asset_url }}"></noscript>
{%- else -%}
  {{ 'section-styles.css' | asset_url | stylesheet_tag }}
{%- endif -%}
```

Test before and after to confirm that you haven't introduced FOUC or CLS.

### Java​Script

Defer scripts that aren't essential for the initial render, such as analytics or chat widgets. The [`script_tag`](https://shopify.dev/docs/api/liquid/filters/script_tag) filter doesn't support `defer` or `async` attributes, so write the `<script>` tag manually with `defer`:

```liquid
<script src="{{ 'theme-interactions.js' | asset_url }}" defer></script>
```

The `defer` attribute tells the browser to download the script in parallel with HTML parsing and execute it after parsing finishes, so it doesn't block rendering.

For more guidance, see [Defer non-critical scripts](https://shopify.dev/docs/storefronts/themes/best-practices/performance/defer-scripts).

### What you can't defer

Some resources aren't under your control as a theme developer, so you can't defer them:

* Shopify injects `content_for_header`, and you can't defer it.
* App scripts injected through the ScriptTag API load independently of theme control. Ask the app developer to use `defer` if a script blocks rendering.
* A/B testing anti-flicker snippets must load synchronously by design, because they prevent a flash of original content before the variant applies. See [Manage A/B testing performance impact](https://shopify.dev/docs/storefronts/themes/best-practices/performance/disable-ab-testing-when-inactive).

### Decide what to defer

Use this table to decide whether a resource is a good candidate for deferral:

| Resource type | Typically deferrable? | How to defer in Shopify |
| - | - | - |
| Section CSS (below fold) | Yes | Async CSS pattern with `section.index` |
| Section CSS (above fold) | No | Keep synchronous |
| Theme interaction JS | Yes | Manual `<script defer>` tag (the `script_tag` filter doesn't support `defer`) |
| Analytics and tracking | Yes | Load after `DOMContentLoaded` or on interaction |
| App scripts (ScriptTag API) | No (not theme-controlled) | Ask app developer to use `defer` |
| `content_for_header` | No | Platform-managed, not deferrable |

***

## Examples

Async CSS pattern for content outside the initial viewport (using the media print trick):

```html
<link
  rel="stylesheet"
  href="non-critical.css"
  media="print"
  onload="this.media='all'"
/>
<noscript><link rel="stylesheet" href="non-critical.css" /></noscript>
```

Use `section.index` for position-aware optimization. See [Use `section.index` for position-aware loading](https://shopify.dev/docs/storefronts/themes/best-practices/performance/use-section-index) for conditional rendering.

***

## Testing

* Use the [Chrome DevTools Performance panel](https://developer.chrome.com/docs/devtools/performance) to identify render-blocking resources. After recording a load, check the **Render blocking requests** section in the **Summary** tab.
* Use the [Chrome DevTools Network panel](https://developer.chrome.com/docs/devtools/network) to visualize the waterfall and identify which resources are delaying the critical path (FCP or LCP).
* Compare FCP before and after your changes.
* Visually inspect the page to confirm that your changes haven't introduced FOUC or new layout shifts.

***

## References

* [Debugging common causes for slow loading in Shopify Liquid storefronts](https://performance.shopify.com/blogs/blog/debugging-common-causes-for-slow-loading-in-shopify-liquid-storefronts)
* [Defer non-critical scripts](https://shopify.dev/docs/storefronts/themes/best-practices/performance/defer-scripts)
* [Load critical CSS synchronously](https://shopify.dev/docs/storefronts/themes/best-practices/performance/load-critical-css-synchronously)
* [Use `section.index` for position-aware loading](https://shopify.dev/docs/storefronts/themes/best-practices/performance/use-section-index)

***
