Critical CSS
Frontend Optimizer generates above-the-fold CSS from the public page URL. It does not use a separate PHP critical-CSS package. The default generator is PlaywrightCriticalCssGenerator, which runs resources/js/generate-critical-css.mjs with the package-local playwright dependency and opens the page in Chromium.
Install the package in a host Capell app with Composer:
composer require capell-app/frontend-optimizerFor local package development, point Composer at ../packages/capell/capell-packages-4/packages/frontend-optimizer as a path repository, then require the same package name.
Generation Flow
Section titled “Generation Flow”PrepareRenderProfileActionreceives the resolved asset sets, render context, optimization scope, and a representative public URL.ResolveRenderProfileActionbuilds a profile signature from assets, context, scope, and critical CSS settings. The hash changes when relevant viewport, fold, or inline-size settings change.- The profile is persisted and
GenerateCriticalCssJobis queued when automatic generation is enabled and no generated CSS exists. GenerateCriticalCssActioncallsCriticalCssGenerator; the default binding isPlaywrightCriticalCssGenerator.- The generator writes a JSON payload containing the target URL, eligible stylesheet paths, configured viewports, fold settings, wait strategy, timeout, and max inline CSS size.
- The Playwright script opens the real URL in Chromium for each viewport and inspects
document.styleSheetsagainst the rendered DOM. - CSS rules are kept when their selectors match visible elements intersecting the configured fold. Matching
@mediaand@supportsrules are preserved around their matching nested rules.@font-faceand keyframes are included. - The generated CSS is stored on the local disk under
capell/frontend-optimizer/critical-css/{profile-hash}.css. - Later renders inline that file as
<style data-critical-css>before profile asset tags.
This URL-based flow is deliberate. It lets the generator see the final Blade output, Layout Builder content, theme markup, package render hooks, responsive CSS, and browser layout instead of guessing from source templates.
Fold And Viewports
Section titled “Fold And Viewports”The configured viewports come from FrontendOptimizerSettings::viewports, falling back to capell-frontend-optimizer.playwright.viewports. The current defaults are:
[ ['width' => 390, 'height' => 844], ['width' => 1440, 'height' => 900],]For each viewport, the script treats an element as above the fold when its visible rectangle intersects:
effectiveFoldHeight = viewportHeight * fold_multiplier + extra_fold_pixelsUse fold_multiplier to include more or less than one screenful. Use extra_fold_pixels for a fixed buffer below the viewport.
Eligible Stylesheets
Section titled “Eligible Stylesheets”Only CSS assets are considered. A stylesheet is eligible when the asset signature marks it as critical_eligible, or when its slot/loading strategy indicates it can affect initial rendering:
base,head, orabove_foldslots unless the loading strategy is lazy, idle, or interaction.critical,blocking, orpreloadloading strategies.
If the profile has no eligible stylesheet paths, the browser-side collector falls back to inspecting all same-origin readable stylesheets.
Fallbacks And Failures
Section titled “Fallbacks And Failures”Public rendering must not block on generation. Until CSS exists, RenderProfileAssetRenderer renders normal stylesheet output for the profile. If generation fails, GenerateCriticalCssAction records the failed run and leaves rendering on the fallback path.
Generated CSS is only inlined when all of these are true:
- critical CSS is enabled in
FrontendOptimizerSettings - the page type has not opted out
- the stored CSS file exists
- the file is within
max_inline_css_bytes
If any check fails, the renderer keeps normal asset tags and omits data-critical-css.
Page Type Opt-Out
Section titled “Page Type Opt-Out”Some page types are not worth optimizing. The package adds a page type setting:
meta.frontend_optimizer.disable_critical_cssWhen this value is true, pages using that page type do not queue generation and do not inline generated critical CSS. The normal profile asset output still renders.
Settings
Section titled “Settings”The extension settings page is backed by FrontendOptimizerSettings and FrontendOptimizerSettingsSchema.
| Setting | Purpose |
|---|---|
frontend_optimizer.enable_critical_css | Enables inline generated CSS. |
frontend_optimizer.automatic_generation | Queues generation when a profile is missing CSS. |
frontend_optimizer.profile_scope | Default optimization scope. |
frontend_optimizer.viewports | Viewport width/height pairs for extraction. |
frontend_optimizer.fold_multiplier | Multiplies viewport height for fold detection. |
frontend_optimizer.extra_fold_pixels | Adds a fixed buffer below the fold. |
frontend_optimizer.playwright_wait_strategy | Browser wait strategy: load, domcontentloaded, or networkidle. |
frontend_optimizer.playwright_timeout | Process timeout in seconds. |
frontend_optimizer.max_inline_css_bytes | Maximum generated CSS size allowed for inline output. |
frontend_optimizer.debug_query_support | Allows non-production debug query support for isolated critical CSS checks. |
The Node binary still comes from config and can be overridden with CAPELL_FRONTEND_OPTIMIZER_NODE.
Verification
Section titled “Verification”Run the package tests from the repository root:
vendor/bin/pest packages/frontend-optimizer/tests --configuration=phpunit.xml