Critical CSS#
With critical_css on, BB Cache inlines the CSS a page needs for its first paint and loads every stylesheet
asynchronously. The plugin does not generate critical CSS. It composes it per page from files that ship in a folder,
normally inside the theme.
Tied to the originating theme. The per-page composition keys on two class patterns from the theme the plugin was built for:
content-section--<layout>on each section andpage-mastheadon the masthead. A theme that does not print these classes getsbase.cssonly. Making the patterns configurable is planned. The legacy per-template scheme described at the end of this page has no such dependency.
The fragment folder#
The folder is the critical_dir setting. Blank means <active theme>/assets/dist/css/critical
(get_stylesheet_directory(), so the child theme when one is active).
| File | Required | Used for |
|---|---|---|
base.css |
Yes. Its presence switches composition on | Rules for everything outside the sections: header, navigation, footer, typography, @font-face |
section-<layout>.css |
One per layout that can appear on a page | Rules for elements inside a section with the class content-section--<layout> |
masthead.css |
When any page prints an element with the class page-masthead |
Rules for the masthead |
post-<ID>.css |
No | Extra rules for one post or page, appended last on that singular view |
Fragments are expected to be minified CSS. A rule used by several layouts should be present in each of their fragments, so every fragment is complete on its own; the duplicates are removed at composition.
How a page is composed#
BB_Cache_Boost::critical_css() runs on the page's HTML during the Boost step:
- It takes the markup from
<body>on and removes<style>,<script>,<noscript>and<template>blocks, so only class names in real markup count. A selector inside an inlined stylesheet is not a section on the page. - It reads every
classattribute that containscontent-section--. The layout name is the part after the prefix, lower-cased, made of letters, digits,_and-, and cut at the first--. For examplecontent-section--quote_callout--shortcodeis the layoutquote_callout. - If the markup contains
page-masthead, the masthead is added. - Layouts are ordered by first appearance in the body.
- The result is
base.css, then each layout's fragment in that order, thenpost-<ID>.cssif it exists. - Duplicate rules are dropped: each rule is kept the first time it appears within the same chain of
@media,@supports,@containeror@layerwrappers.@font-faceand@keyframesblocks are kept whole. - The
bb_cache_critical_cssfilter receives the composed CSS and the HTML.
Then, in the page:
- The CSS is inlined as
<style id="bb-critical">and moved up in the head, to just before the first<link>,<style>or<script>(BB Cache's own inline loader scripts excepted), so it follows the charset and viewport metas. - Every
<link rel="stylesheet">is switched tomedia="print"with anonloadhandler that restores its media value. The original links are repeated inside a<noscript>before</head>. - Links that already have an
onloadattribute, havedata-no-async, or aremedia="print"are left alone.
Page-scoped stylesheets#
Stylesheets that apply to one page or a few pages cannot be part of the shared fragments. Loaded asynchronously they
would arrive late and shift what they style. The critical_inline setting lists such sheets by a substring or regex
of their href. A matching sheet is inlined whole as <style data-bb-inline="<file name>"> when it is a local file
of at most 24 KB (24,576 bytes). Relative url() paths are rewritten and any </style text in the sheet is escaped.
Larger or non-local sheets fall back to the async treatment.
The default list is site-specific. Replace it with the paths of your own page-scoped sheets. See the settings reference.
When a fragment is missing#
If a section's layout has no section-<layout>.css (or the page has a masthead and there is no masthead.css), the
page gets no critical CSS at all:
- nothing is inlined and the stylesheets stay render-blocking
- the head carries a marker naming the layouts
<meta name="bb-critical" content="no fragment for pricing_table, logo_wall">
Blocking stylesheets only delay the first paint. An incomplete inline block would let a section paint unstyled and then re-lay out when its sheet arrives, which is a layout shift of up to a full viewport. The plugin prefers the slower, stable page.
One exception: a layout without a fragment counts as covered when the same class attribute also carries a layout
that has one. This covers sections that print two layout classes.
To find affected pages, search the HTML for the marker:
curl -s https://example.com/pricing/ | grep -o '<meta name="bb-critical"[^>]*>'
The marker is a meta tag, not a comment, because HTML minify removes comments.
Generating the fragments#
The generator is not part of this plugin yet. It lives in the originating project as tools/critical-css.js, a
Node script that drives headless Chrome. The description below comes from that project's notes; it cannot be checked
against this repository.
- It renders a list of sample pages (a few per layout, plus mastheads and listing pages) and assigns each rule of the
theme's own stylesheets to a file by where the matching elements live: outside any section goes to
base.css, insidecontent-section--<layout>tosection-<layout>.css, inside.page-mastheadtomasthead.css. - Single-class rules of the theme's core sheet go to
base.csswhether or not a sample page used them, so a utility class an editor turns on later is covered. - The fragments are written into the theme's
assets/dist/css/criticalfolder and deployed with the theme. Nothing is generated on the server.
Until the generator ships with the plugin, you need your own way to produce the files. Any tool that yields the layout described under The fragment folder works; so does the legacy scheme below with any critical CSS tool that writes one file per template.
Regenerate after a change to the theme's CSS or templates: the inline copy does not update itself. Content changes need no regeneration unless a page starts using a layout that has no fragment.
Checking what exists#
Settings → BB Cache → Tools lists the folder and the files found with their size and age.
wp bb-cache critical status
Legacy scheme: one file per template#
While the folder has no base.css, the earlier scheme applies. The page gets the contents of one file:
post-<ID>.csson a singular view, if it exists- otherwise
<key>.css
| Request | Key |
|---|---|
| Front page | home |
| Page with a page template | tpl-<template slug> (the template file name without templates/ and .php) |
| Page without a template | page |
| Other singular | single-<post type> |
| Post type archive | archive-<post type> |
| Category, tag or taxonomy archive | tax-<taxonomy> |
| Posts page | blog |
| Search | search |
| 404 | 404 |
| Anything else | page |
The bb_cache_critical_key filter can change the key. wp bb-cache critical targets prints up to three sample URLs
per key as JSON, as input for a generator. If no file matches, the page keeps blocking stylesheets; this scheme
writes no marker.
The per-section scheme replaced this one because pages of one template can differ in their sections: critical CSS generated from a few sample pages of a template missed sections that only other pages of that template carried.