A PostCSS plugin that takes existing CSS files and splits out the annotated critical styles into a separate file, inspired by https://github.com/wladston/postcss-split
critical
, rest
and input
. This can be used to choose which type of output you'd like to generate.For larger scale projects, automating critical-CSS detection is complicated, unprecise or damn-nearly impossible. Annotating your CSS with a simple comment gives your perfect control over which CSS rules are to be considered critical and which ones are not.
If you later decide to no longer support this workflow or switch to a different one (with different tools), the critical-comments are standard CSS and will not break your project.
The idea here is that we want to generate our entire CSS file first and then split out what is considered 'critical'. Injecting it into an HTML file right away would be fairly dictative of your workflow. This allows for more flexible setups.
For example: during development you could <link>
the critical-CSS file, while rendering it out into the HTML templates once you get ready for production (remember to adjust the URL's in the CSS file for the changed context of the CSS execution).
npm install --save-dev postcss postcss-critical-split
To run tests:
npm test
If you want to contribute to the project and write additional tests, look into the testsuite folder. You'll find a folder per test with input/output results, splitSettings and optional process tasks where you can write a custom test scenario.
gulp.src(['**/*.css','!**/*-critical.css'])
.pipe(postcss(require('postcss-critical-split')));
/* before: main.css */
/* critical:start */
header{
background-color: #1d1d1d;
font-size: 2em;
}
.aside {
text-decoration: underline;
}
/* critical:end */
p {
font-size: 14px;
}
li {
float: left;
/* critical:start */
color: red;
/* critical:end */
}
footer{
background-color: #1d1d1d;
font-size: 1.1em;
}
a[rel=external]:before{
content: '[!]';
/* critical */
}
/* critical:start */
@media screen and (min-width: 400px) {
footer {
padding: 50px;
}
}
/* critical:end */
@media screen and (min-width: 1400px) {
header {
height: 300px;
/* critical:start */
background-color: #FF0066;
font-size: 3em;
/* critical:end */
}
}
/* after: main.css */
p {
font-size: 14px;
}
li {
float: left;
}
footer{
background-color: #1d1d1d;
font-size: 1.1em;
}
@media screen and (min-width: 1400px) {
header {
background-color: #FF0066;
font-size: 3em;
}
}
/* after main-critical.css */
header{
background-color: #1d1d1d;
font-size: 2em;
}
.aside {
text-decoration: underline;
}
li {
color: red;
}
a[rel=external]:before{
content: '[!]';
}
@media screen and (min-width: 400px) {
footer {
padding: 50px;
}
}
@media screen and (min-width: 1400px) {
header {
background-color: #FF0066;
font-size: 3em;
}
}
This plugin supports important comments (e.g. /*! critical */
). Any of the
examples above should work using this comment style.
The plugin accepts an object with additional options.
defaults to critical
Allowed values: critical
, rest
or input
to return either the critical-css, the rest-css or just the original input-css.
defaults to critical
This is the comment text that is matched in every rule/atRule in the original CSS file. If the blockTag is encountered in a rule, the rule is appended to the critical-CSS file and removed in the original file. All declarations in the rule will be carried over.
/* gulpfile */
gulp.src(['**/*.css','!**/*-critical.css'])
.pipe(postcss(require('postcss-critical-split')({
'blockTag':'criticalCss'
}));
/* before: main.css */
header{
/* criticalCss */
background-color: #1d1d1d;
font-size: 2em;
}
footer{
background-color: #1d1d1d;
font-size: 1.1em;
}
/* after: main.css */
footer{
background-color: #1d1d1d;
font-size: 1.1em;
}
/* after: main-critical.css */
header{
background-color: #1d1d1d;
font-size: 2em;
}
startTag defaults to critical:start
endTag defaults to critical:end
These are the comment texts that are matched throughout the original CSS file. If the startTag is encountered, every rule, declaration, atRule is carried into the critical-CSS until the endTag is encountered. All the rules that appy will be removed from the original CSS.
/* gulpfile */
gulp.src(['**/*.css','!**/*-critical.css'])
.pipe(postcss(require('postcss-critical-split')({
'startTag':'grab:open',
'endTag':'grab:close',
}));
/* before: main.css */
/* grab:open */
header{
background-color: #1d1d1d;
font-size: 2em;
}
.aside {
text-decoration: underline;
}
/* grab:close */
footer{
background-color: #1d1d1d;
font-size: 1.1em;
}
/* after: main.css */
footer{
background-color: #1d1d1d;
font-size: 1.1em;
}
/* after: main-critical.css */
header{
background-color: #1d1d1d;
font-size: 2em;
}
.aside {
text-decoration: underline;
}
null
, should be an array of strings*These are the modules you want to select from your css file into the critical file. This allows for targetting which parts of the CSS to include in the critical and which ones not. CSS rules that are not labeled by a module will be considered 'common' and thus will be added to the critical CSS at all times.
/* gulpfile */
gulp.src(['**/*.css','!**/*-critical.css'])
.pipe(postcss(require('postcss-critical-split')({
'modules': ['header', 'top-photo']
}));
/* before: main.css */
/* critical:start:header */
header{
background-color: #1d1d1d;
font-size: 2em;
}
/* critical:end */
.login-button {
display: block;
border: red thin solid;
}
/* critical:start:top-photo */
.top-photo{
background-color: #1d1d1d;
font-size: 2em;
}
/* critical:end */
/* critical:start:preview-article */
.preview-article{
color: #CCC;
}
/* critical:end */
/* critical:start */
.profile-picture{
float: right;
width: 20%;
height: auto;
}
/* critical:end */
.aside {
text-decoration: underline;
}
footer{
background-color: #1d1d1d;
font-size: 1.1em;
}
/* after: main.css */
.login-button {
display: block;
border: red thin solid;
}
.preview-article{
color: #CCC;
}
.aside {
text-decoration: underline;
}
footer{
background-color: #1d1d1d;
font-size: 1.1em;
}
/* after: main-critical.css */
header{
background-color: #1d1d1d;
font-size: 2em;
}
.top-photo{
background-color: #1d1d1d;
font-size: 2em;
}
.aside {
text-decoration: underline;
}
footer{
background-color: #1d1d1d;
font-size: 1.1em;
}
:
*This is the separator used in your critical start-tag to tag a module.
/* gulpfile */
gulp.src(['**/*.css','!**/*-critical.css'])
.pipe(postcss(require('postcss-critical-split')({
'modules': ['header', 'top-photo'],
'separator': '--'
}));
/* critical:start--header */