Optimizing Critical CSS for 1C-Bitrix
Typical scenario: a Bitrix site loads three to four CSS files totaling 300–600 KB. The browser blocks rendering until all CSS is loaded — this is called render-blocking. As a result, FCP reaches 3–5 s on a mobile connection even with caching. We solve this problem by extracting critical CSS and inlining it. Assess your project — contact us for a consultation.
Why does render-blocking CSS occur in Bitrix?
Bitrix generates a list of CSS files via CMain::AddCSS() and outputs them in <head> as <link rel="stylesheet">. All files block rendering. The built-in combiner (/bitrix/cache/css/) merges CSS but does not separate critical from non-critical. Components like bitrix:catalog.section add their own styles via $APPLICATION->SetAdditionalCSS(). Everything ends up in the blocking path. As a result, even with caching, the first screen renders with a delay.
What is critical CSS in practice?
Critical CSS is the styles needed for content above the fold without additional requests. For a Bitrix site, this includes: reset (box-sizing, basic margins), header and first block grid, H1–H2 typography, navigation menu, hero banner styles. The rest — product cards, cart, filters, footer — load asynchronously. Inlining critical CSS reduces FCP by 40–60%, as confirmed by Google's web.dev measurement.
Technique for inlining critical CSS
Step 1: Extract critical styles
Use the critical utility (Node.js):
npm install -g critical critical https://example.com --width=1300 --height=900 \ --css=public/bitrix/templates/main/template_styles.css \ --inline \ --output=critical.css For mobile viewport, add a second run with parameters --width=375 --height=812. The combined result is a file of 15–40 KB.
Step 2: Integrate into Bitrix template
In the template's header.php:
<?php $criticalCss = file_get_contents(__DIR__ . '/critical.css'); ?> <style><?= $criticalCss ?></style> <link rel="preload" href="/local/templates/main/template_styles.css" as="style" onload="this.onload=null;this.rel='stylesheet'"> <noscript> <link rel="stylesheet" href="/local/templates/main/template_styles.css"> </noscript> rel="preload" as="style" with switching via onload is the standard LoadCSS pattern. <noscript> is a fallback for browsers without JavaScript.
Step 3: Work with Bitrix CSS combiner
If the combiner is enabled (BX_COMPOSITE_BUFFER_ON_CSS), it intercepts <link> output. Either disable it for controlled files:
define('BX_COMPOSITE_BUFFER_ON_CSS', false); Or use the OnEndBufferContent event to replace blocking <link> tags with asynchronous ones.
PurgeCSS and PostCSS: reduce CSS by 60–80%
On projects with Gulp or Webpack, add:
const purgecss = require('@fullhuman/postcss-purgecss'); postcss([ purgecss({ content: ['./local/templates/**/*.php', './local/components/**/*.php'], defaultExtractor: content => content.match(/[\w-/:]+(?<!:)/g) || [] }) ]) PurgeCSS analyzes PHP templates and removes unused rules. On Bootstrap/Foundation themes, CSS shrinks from 250 KB to 30–60 KB. Combining inline critical CSS with PurgeCSS gives the best result — according to MDN, FCP drops by 1–2 s on average.
Case: corporate portal on Bitrix24 (from our practice)
A company portal with ~300 employees: the main page loaded 7 CSS files (480 KB). FCP in Lighthouse (Desktop, Fast 3G) — 4.2 s. The goal was to reach 1.5 s without changing the template. Our engineer with over 5 years of experience performed:
- Run
criticalfor the main page, news section, and documents — three different sets of critical CSS. - In
header.php, added logic to determine the page type and load the corresponding inline CSS. - Converted remaining CSS files to
preload+ async loading. - PurgeCSS removed ~60% of unused rules from
template_styles.css.
Result: FCP — 1.3 s, total CSS weight "above the fold" — 18 KB inline, remaining 90 KB async after paint.
How to automate critical CSS updates?
Critical CSS needs updating with every design change. Integrate into deployment:
#!/bin/bash node ./scripts/generate-critical.js php artisan cache:clear The script generate-critical.js (Puppeteer) generates critical CSS for a list of key pages and writes files to the template folder.
Diagnosing effectiveness
In Chrome DevTools → Coverage (Shift+Ctrl+P → Coverage), see the percentage of unused CSS. A value >70% on the first screen signals optimization need. In Lighthouse, the "Reduce unused CSS" metric shows potential savings in KB. We guarantee: after our optimization, unused CSS drops to 10–15%.
What's included in the "turnkey" service
| Component | Details |
|---|---|
| Current CSS audit | Check Coverage, identify render-blocking files |
| Critical CSS extraction | For 3–5 typical pages with different viewports |
| Integration into template | Inline in header.php, async loading of the rest |
| PurgeCSS (optional) | Configure in pipeline, remove unused rules |
| Testing | Verify FCP, LCP, CLS on real devices |
| Documentation | Instructions for updating critical CSS on changes |
Timeline and cost
| Scale | Scope | Duration |
|---|---|---|
| Basic | Manual CSS extraction + inline in header.php | 2–3 days |
| Medium | Automation via critical + async link + deployment | 4–6 days |
| Full | PurgeCSS in build, multiple critical CSS sets for different page types, CI integration | 7–10 days |
Example code for generating critical CSS via Puppeteer
const puppeteer = require('puppeteer'); const critical = require('critical'); async function generateCritical(url, cssPath, outputPath) { const browser = await puppeteer.launch(); const page = await browser.newPage(); await page.goto(url, { waitUntil: 'networkidle0' }); const css = await critical.generate({ inline: false, css: [cssPath], width: 1300, height: 900, }); require('fs').writeFileSync(outputPath, css); await browser.close(); } Order critical CSS optimization for your Bitrix site. Our certified specialists (5+ years of experience, 50+ projects) will bring FCP down to 1.5 s. Get a consultation — write to us!

