# Move CSS above scripts (move_css_above_scripts)

Moves CSS link above script tags. The move_css_above_scripts filter: what it does, its risks and the Apache, nginx and IIS directives.

Canonical URL: https://modpagespeed.com/docs/filters/move_css_above_scripts/

- Category: CSS
- CoreFilters: No
- OptimizeForBandwidth: No
- Risk: Generally safe

`move_css_above_scripts` lifts stylesheet references that sit below the page's first `<script>` up to just before that first script. A browser will not run a script until the stylesheets above it have loaded, because the script may read layout; with stylesheets scattered around and below scripts, those downloads are discovered late and the script waits on them. Moving each stylesheet directly before the first script puts every download in front of the code that needs it.

## How it works

Not a core filter; enable it by name. Live demo: [move_css_above_scripts](https://modpagespeed.com/examples/move_css_above_scripts/).

### When it helps and when it does not

It helps on legacy or machine-generated pages where stylesheets ended up interleaved with or after scripts: template fragments that each carry their own `<link>`, or ad and widget snippets injecting CSS late in the body. On pages whose CSS already sits in `<head>` with scripts at the end of `<body>`, there is nothing after any script to move and the filter changes nothing. The stylesheets keep their order among themselves, so the cascade is unchanged; what changes is where the group sits relative to the script.

### How it decides

The first `<script>` in the document is the anchor. Every `<style>` block and stylesheet `<link>` that appears after it moves to directly before that first script, in original order. When `move_css_to_head` is also enabled, whichever anchor closes first in the document, the `</head>` or the first script, wins and all moves go there. A stylesheet inside `<noscript>`, or a `<style scoped>` block, stays where it is and ends the current move; styles after it move up only as far as the next `<script>`.

## When to use it

- Not in CoreFilters: it runs only when you enable it by name.
- Risk rating on these docs: **Generally safe**.

## Risks

- A stylesheet deliberately placed after a script by code that removes or replaces it at run time is moved too; such pages need the filter off for that path.

- Verify with the `X-Mod-Pagespeed` response header and a `?PageSpeedFilters=-move_css_above_scripts` comparison; [Is it working?](https://modpagespeed.com/docs/is-it-working/) has the steps.

## Configuration

Enable it in the module configuration, at server, virtual-host or location scope:

**Apache**

```apache
ModPagespeedEnableFilters move_css_above_scripts
```

**nginx**

```nginx
pagespeed EnableFilters move_css_above_scripts;
```

**IIS (pagespeed.config)**

```text
pagespeed EnableFilters move_css_above_scripts
```

```html
<!-- before -->
<script src="/js/theme.js"></script>
<link rel="stylesheet" href="/css/theme.css" />

<!-- after: the stylesheet loads first -->
<link rel="stylesheet" href="/css/theme.css" />
<script src="/js/theme.js"></script>
```

### On the worker

The worker runs its own pipeline, configured by flags. Its equivalent of this filter is the [async css](https://modpagespeed.com/docs/worker-configuration/#async-css) transform. Toggleable via [`--no-async-css`](https://modpagespeed.com/docs/worker-configuration/#--no-async-css); the coverage gate is tuned with [`--async-css-min-coverage`](https://modpagespeed.com/docs/worker-configuration/#--async-css-min-coverage) and [`--async-css-min-deferred-bytes`](https://modpagespeed.com/docs/worker-configuration/#--async-css-min-deferred-bytes).

Scoping, `ForbidFilters` and the thresholds filters read: [Choosing filters](https://modpagespeed.com/docs/filter-selection/).

## Live example

See the before and after, with the source diff: [move_css_above_scripts example](https://modpagespeed.com/examples/move_css_above_scripts/).

## Frequently asked questions

**What does the move_css_above_scripts filter do?**

`move_css_above_scripts` lifts stylesheet references that sit below the page's first `<script>` up to just before that first script. A browser will not run a script until the stylesheets above it have loaded, because the script may read layout; with stylesheets scattered around and below scripts, those downloads are discovered late and the script waits on them. Moving each stylesheet directly before the first script puts every download in front of the code that needs it.

**Is move_css_above_scripts enabled by default?**

No. `move_css_above_scripts` is not in CoreFilters, the default RewriteLevel; it runs only when you enable it by name with `EnableFilters`.

**How do I enable move_css_above_scripts on Apache and nginx?**

Add `ModPagespeedEnableFilters move_css_above_scripts` on Apache or `pagespeed EnableFilters move_css_above_scripts;` on nginx. On IIS, add `pagespeed EnableFilters move_css_above_scripts` to pagespeed.config.

## Related filters

- [`combine_css`](https://modpagespeed.com/docs/filters/combine_css/): Combine CSS
- [`compute_critical_css`](https://modpagespeed.com/docs/filters/compute_critical_css/): Compute critical CSS
- [`extend_cache_css`](https://modpagespeed.com/docs/filters/extend_cache_css/): Extend cache for CSS
- [`fallback_rewrite_css_urls`](https://modpagespeed.com/docs/filters/fallback_rewrite_css_urls/): Fallback CSS URL rewriting
- [`flatten_css_imports`](https://modpagespeed.com/docs/filters/flatten_css_imports/): Flatten CSS @imports
- [`inline_css`](https://modpagespeed.com/docs/filters/inline_css/): Inline CSS
- [`inline_google_font_css`](https://modpagespeed.com/docs/filters/inline_google_font_css/): Inline Google Fonts CSS
- [`inline_import_to_link`](https://modpagespeed.com/docs/filters/inline_import_to_link/): Convert @import to link

This page is drawn from the [move_css_above_scripts entry on CSS filters](https://modpagespeed.com/docs/css-filters/#move_css_above_scripts). Every filter in one table: [PageSpeed filters](https://modpagespeed.com/docs/filters/).
