Critical

Extract & Inline Critical-path CSS in HTML pages

README

[![NPM version][npm-image]][npm-url] [![Build Status][ci-image]][ci-url] [![Coverage][coveralls-image]][coveralls-url]

critical


Critical extracts & inlines critical-path (above-the-fold) CSS from HTML

Preview

Install


  1. ```sh
  2. npm i -D critical
  3. ```

Build plugins


- Gulp users should use Critical directly

Demo projects



Usage


Include:

  1. ``` js
  2. import {generate} from 'critical';
  3. ```

Full blown example with available options:

  1. ``` js
  2. generate({
  3.   // Inline the generated critical-path CSS
  4.   // - true generates HTML
  5.   // - false generates CSS
  6.   inline: true,

  7.   // Your base directory
  8.   base: 'dist/',

  9.   // HTML source
  10.   html: '<html>...</html>',

  11.   // HTML source file
  12.   src: 'index.html',

  13.   // Your CSS Files (optional)
  14.   css: ['dist/styles/main.css'],

  15.   // Viewport width
  16.   width: 1300,

  17.   // Viewport height
  18.   height: 900,

  19.   // Output results to file
  20.   target: {
  21.     css: 'critical.css',
  22.     html: 'index-critical.html',
  23.     uncritical: 'uncritical.css',
  24.   },

  25.   // Extract inlined styles from referenced stylesheets
  26.   extract: true,

  27.   // ignore CSS rules
  28.   ignore: {
  29.     atrule: ['@font-face'],
  30.     rule: [/some-regexp/],
  31.     decl: (node, value) => /big-image\.png/.test(value),
  32.   },
  33. });
  34. ```

Generate and inline critical-path CSS


Basic usage:

  1. ``` js
  2. generate({
  3.   inline: true,
  4.   base: 'test/',
  5.   src: 'index.html',
  6.   target: 'index-critical.html',
  7.   width: 1300,
  8.   height: 900,
  9. });
  10. ```

Generate critical-path CSS


Basic usage:

  1. ``` js
  2. generate({
  3.   base: 'test/',
  4.   src: 'index.html',
  5.   target: 'styles/main.css',
  6.   width: 1300,
  7.   height: 900,
  8. });
  9. ```

Generate and minify critical-path CSS:

  1. ``` js
  2. generate({
  3.   base: 'test/',
  4.   src: 'index.html',
  5.   target: 'styles/styles.min.css',
  6.   width: 1300,
  7.   height: 900,
  8. });
  9. ```

Generate, minify and inline critical-path CSS:

  1. ``` js
  2. generate({
  3.   inline: true,
  4.   base: 'test/',
  5.   src: 'index.html',
  6.   target: {
  7.     html: 'index-critical.html',
  8.     css: 'critical.css',
  9.   },
  10.   width: 1300,
  11.   height: 900,
  12. });
  13. ```

Generate and return output via callback:

  1. ``` js
  2. generate({
  3.     base: 'test/',
  4.     src: 'index.html',
  5.     width: 1300,
  6.     height: 900,
  7.     inline: true
  8. }, (err, {css, html, uncritical}) => {
  9.     // You now have critical-path CSS as well as the modified HTML.
  10.     // Works with and without target specified.
  11.     ...
  12. });
  13. ```

Generate and return output via promise:

  1. ``` js
  2. generate({
  3.     base: 'test/',
  4.     src: 'index.html',
  5.     width: 1300,
  6.     height: 900
  7. }).then((({css, html, uncritical})) => {
  8.     // You now have critical-path CSS as well as the modified HTML.
  9.     // Works with and without target specified.
  10.     ...
  11. }).error(err => {
  12.     ...
  13. });
  14. ```

Generate and return output via async function:

  1. ``` js
  2. const {css, html, uncritical} = await generate({
  3.   base: 'test/',
  4.   src: 'index.html',
  5.   width: 1300,
  6.   height: 900,
  7. });
  8. ```

Generate critical-path CSS with multiple resolutions


When your site is adaptive and you want to deliver critical CSS for multiple screen resolutions this is a useful option.
_note:_ (your final output will be minified as to eliminate duplicate rule inclusion)

  1. ``` js
  2. generate({
  3.   base: 'test/',
  4.   src: 'index.html',
  5.   target: {
  6.     css: 'styles/main.css',
  7.   },
  8.   dimensions: [
  9.     {
  10.       height: 200,
  11.       width: 500,
  12.     },
  13.     {
  14.       height: 900,
  15.       width: 1200,
  16.     },
  17.   ],
  18. });
  19. ```

Generate critical-path CSS and ignore specific selectors


This is a useful option when you e.g. want to defer loading of webfonts or background images.

  1. ``` js
  2. generate({
  3.   base: 'test/',
  4.   src: 'index.html',
  5.   target: {
  6.     css: 'styles/main.css',
  7.   },
  8.   ignore: {
  9.     atrule: ['@font-face'],
  10.     decl: (node, value) => /url\(/.test(value),
  11.   },
  12. });
  13. ```

Generate critical-path CSS and specify asset rebase behaviour


  1. ``` js
  2. generate({
  3.   base: 'test/',
  4.   src: 'index.html',
  5.   target: {
  6.     css: 'styles/main.css',
  7.   },
  8.   rebase: {
  9.     from: '/styles/main.css',
  10.     to: '/folder/subfolder/index.html',
  11.   },
  12. });
  13. ```

  1. ``` js
  2. generate({
  3.   base: 'test/',
  4.   src: 'index.html',
  5.   target: {
  6.     css: 'styles/main.css',
  7.   },
  8.   rebase: asset => `https://my-cdn.com${asset.absolutePath}`,
  9. });
  10. ```

Options


NameTypeDefaultDescription
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
inline`boolean`\|`object``false`Inline
base`string``path.dirname(src)`Base
html`string`|
css`array``[]`An
src`string`|
target`string`|
width`integer``1300`Width
height`integer``900`Height
dimensions`array``[]`An
extract`boolean``false`Remove
inlineImages`boolean``false`Inline
assetPaths`array``[]`List
maxImageFileSize`integer``10240`Sets
rebase`object``undefined`Critical
ignore`array``object``undefined`
userAgent`string``''`User
penthouse`object``{}`Configuration
request`object``{}`Configuration
user`string``undefined`RFC2617
pass`string``undefined`RFC2617
strict`boolean``false`Throw

CLI


  1. ```sh
  2. npm install -g critical
  3. ```

critical works well with standard input.

  1. ```sh
  2. cat test/fixture/index.html | critical --base test/fixture --inline > index.critical.html
  3. ```

Or on Windows:

  1. ```bat
  2. type test\fixture\index.html | critical --base test/fixture --inline > index.critical.html
  3. ```

You can also pass in the critical CSS file as an option.

  1. ```sh
  2. critical test/fixture/index.html --base test/fixture > critical.css
  3. ```

Gulp


  1. ``` js
  2. import gulp from 'gulp';
  3. import log from 'fancy-log';
  4. import {stream as critical} from 'critical';

  5. // Generate & Inline Critical-path CSS
  6. gulp.task('critical', () => {
  7.   return gulp
  8.     .src('dist/*.html')
  9.     .pipe(
  10.       critical({
  11.         base: 'dist/',
  12.         inline: true,
  13.         css: ['dist/styles/components.css', 'dist/styles/main.css'],
  14.       })
  15.     )
  16.     .on('error', err => {
  17.       log.error(err.message);
  18.     })
  19.     .pipe(gulp.dest('dist'));
  20. });
  21. ```

Why?


Why is critical-path CSS important?


CSS is required to construct the render tree for your pages and JavaScript

will often block on CSS during initial construction of the page.

You should ensure that any non-essential CSS is marked as non-critical

(e.g. print and other media queries), and that the amount of critical CSS

and the time to deliver it is as small as possible.


Why should critical-path CSS be inlined?


For best performance, you may want to consider inlining the critical CSS

directly into the HTML document. This eliminates additional roundtrips

in the critical path and if done correctly can be used to deliver a

“one roundtrip” critical path length where only the HTML is a blocking resource.


FAQ


Are there any sample projects available using Critical?


Why, yes!. Take a look at this Gulp project
which demonstrates using Critical to generate and inline critical-path CSS. It also includes a mini-tutorial
that walks through how to use it in a simple webapp.

When should I just use Penthouse directly?


The main differences between Critical and Penthouse, a module we
use, are:

- Critical will automatically extract stylesheets from your HTML from which to generate critical-path CSS from,
  whilst other modules generally require you to specify this upfront.
- Critical provides methods for inlining critical-path CSS (a common logical next-step once your CSS is generated)
- Since we tackle both generation and inlining, we're able to abstract away some of the ugly boilerplate otherwise
  involved in tackling these problems separately.

That said, if your site or app has a large number of styles or styles which are being dynamically injected into
the DOM (sometimes common in Angular apps) I recommend using Penthouse directly. It will require you to supply
styles upfront, but this may provide a higher level of accuracy if you find Critical isn't serving your needs.

What other alternatives to Critical are available?


FilamentGroup maintain a criticalCSS node module, which
similar to Penthouse will find and output the critical-path CSS for
your pages. The PageSpeed Optimization modules for nginx, apache, IIS, ATS, and Open Lightspeed can do all the heavy
lifting automatically when you enable the prioritize_critical_css filter

Is Critical stable and suitable for production use?


Critical has been used on a number of production sites that have found it stable for everyday use.
That said, we welcome you to try it out on your project and report bugs if you find them.

Can I contribute?


Of course. We appreciate all of our contributors and
welcome contributions to improve the project further. If you're uncertain whether an addition should be made, feel
free to open up an issue and we can discuss it.

Maintainers


This module is brought to you and maintained by the following people:

- Addy Osmani - Creator (Github / Twitter)
- Ben Zörb - Primary maintainer (Github / Twitter)

License



[npm-url]: https://www.npmjs.com/package/critical
[npm-image]: https://img.shields.io/npm/v/critical.svg
[ci-url]: https://github.com/addyosmani/critical/actions?workflow=Tests
[ci-image]: https://github.com/addyosmani/critical/workflows/Tests/badge.svg
[coveralls-url]: https://coveralls.io/github/addyosmani/critical?branch=master
[coveralls-image]: https://img.shields.io/coveralls/github/addyosmani/critical/master.svg