Skip to main content
The Critical CSS plugin automatically extracts and inlines critical above-the-fold CSS directly into your HTML pages. This optimization technique dramatically improves initial page load performance by eliminating render-blocking CSS.

Overview

The Critical CSS plugin:
  • Analyzes your rendered HTML pages
  • Extracts critical above-the-fold CSS
  • Inlines critical CSS into the <head>
  • Adds preload tags for full stylesheets
  • Supports custom viewport dimensions
  • Minifies inlined CSS automatically

Installation

The Critical CSS plugin is a built-in Scully plugin and requires no separate installation.

Configuration

Register and configure the plugin in your scully.config.ts:
import { ScullyConfig, setPluginConfig } from '@scullyio/scully';
import { criticalCSS } from '@scullyio/scully-plugin-critical-css';

export const config: ScullyConfig = {
  // Your routes configuration
};

// Configure Critical CSS plugin
setPluginConfig(criticalCSS, {
  inlineImages: true,
  width: 1920,
  height: 1080
});

Configuration Options

inlineImages
boolean
default:true
Inline images into the pages when smaller than 10240 bytes (10KB). This reduces HTTP requests for small images.
width
number
default:1800
Width of the target viewport in pixels. Used to determine which CSS is “above the fold”.
height
number
default:1400
Height of the target viewport in pixels. Used to determine which CSS is “above the fold”.
dimensions
array
An array of viewport dimension objects. Takes precedence over width and height if set.
dimensions: [
  { width: 1920, height: 1080 },
  { width: 768, height: 1024 },
  { width: 375, height: 667 }
]
assets
string[]
An array of fully qualified paths to asset directories. If not provided, defaults to [outDir, outDir/assets].
assets: [
  '/path/to/static',
  '/path/to/assets'
]
ignore
object
Specify CSS rules to ignore during critical CSS extraction.
ignore: {
  atrule: ['@font-face'],
  rule: ['.ignore-this'],
  decl: (node, value) => {
    // Custom logic to ignore declarations
    return /big-image/.test(value);
  }
}

Usage Examples

Basic Configuration

Minimal setup with default options:
import { criticalCSS } from '@scullyio/scully-plugin-critical-css';
import { setPluginConfig } from '@scullyio/scully';

setPluginConfig(criticalCSS, {
  inlineImages: true
});

Mobile-First Configuration

Optimize for mobile viewports:
setPluginConfig(criticalCSS, {
  width: 375,
  height: 667,
  inlineImages: true
});

Multi-Device Configuration

Generate critical CSS for multiple viewport sizes:
setPluginConfig(criticalCSS, {
  dimensions: [
    { width: 375, height: 667 },   // Mobile
    { width: 768, height: 1024 },  // Tablet
    { width: 1920, height: 1080 }  // Desktop
  ],
  inlineImages: true
});

Custom Asset Paths

Specify custom locations for static assets:
setPluginConfig(criticalCSS, {
  inlineImages: true,
  assets: [
    '/dist/static',
    '/dist/images',
    '/dist/fonts'
  ]
});

Ignore Specific CSS

Exclude certain CSS rules from critical extraction:
setPluginConfig(criticalCSS, {
  ignore: {
    atrule: ['@font-face', '@keyframes'],
    rule: ['.print-only', '.admin-panel'],
    decl: (node, value) => {
      // Ignore declarations with large background images
      return /url\(.*large.*\)/.test(value);
    }
  }
});

How It Works

  1. HTML Analysis: After Scully renders a page, the plugin analyzes the HTML
  2. CSS Discovery: All CSS files in the dist folder are found and read
  3. Viewport Simulation: The page is rendered in a headless browser at specified dimensions
  4. Critical Extraction: CSS required for above-the-fold rendering is identified
  5. Inline Injection: Critical CSS is minified and injected into the <head>
  6. Preload Addition: Original stylesheets are preloaded for lazy loading
  7. Image Inlining: Small images are converted to data URIs if enabled

Output Example

Before Critical CSS plugin:
<head>
  <link rel="stylesheet" href="styles.css">
</head>
After Critical CSS plugin:
<head>
  <style>
    /* Minified critical CSS inlined here */
    body{margin:0;font-family:sans-serif}header{height:80px}
  </style>
  <link rel="preload" href="styles.css" as="style">
  <link rel="stylesheet" href="styles.css">
</head>

Performance Benefits

Faster First Paint

Critical CSS eliminates render-blocking resources, showing content to users faster.

Reduced Layout Shifts

Inlined CSS ensures proper layout before external stylesheets load.

Better Lighthouse Scores

Improves Performance and Best Practices scores.

Improved User Experience

Faster perceived load times lead to better user engagement.

When to Use

The Critical CSS plugin is beneficial when:
  • You have large CSS files
  • First paint performance is critical
  • You want to improve Lighthouse scores
  • You’re building content-heavy sites
  • SEO performance matters
The Critical CSS plugin increases build time because it processes each page individually. For large sites, consider using it selectively on important pages.

Best Practices

1

Test viewport dimensions

Choose viewport dimensions that match your primary audience’s devices.
2

Monitor build times

Critical CSS extraction adds processing time. Balance optimization with build speed.
3

Verify output

Check a few generated pages to ensure critical CSS looks correct.
4

Use with lazy loading

Combine with lazy loading strategies for non-critical resources.

Error Handling

If critical CSS extraction fails for a route:
  • A warning is logged with the route information
  • The original HTML is returned unchanged
  • The build continues with other routes
route: "/blog/post" could not inline CSS
Failed critical CSS extraction doesn’t break your site—it simply means that route won’t have optimized CSS inlining.

Limitations

  • No CSS Extraction: The plugin doesn’t remove critical CSS from full stylesheets (to ensure SPA functionality)
  • Build Time: Processing time increases with page count and CSS size
  • Static Analysis: Only analyzes static rendered HTML, not dynamic JavaScript-rendered content

Troubleshooting

  • Verify CSS files exist in the dist folder
  • Check that outDir is correctly configured
  • Ensure CSS files are generated before Scully runs
  • Reduce viewport dimensions array
  • Disable image inlining with inlineImages: false
  • Consider selective application to important routes only
  • Ensure images are smaller than 10KB
  • Verify inlineImages: true is set
  • Check that asset paths are correct

Flash Prevention Plugin

Prevent flash of unstyled content

Performance Optimization

Learn more optimization techniques

Build docs developers (and LLMs) love