Optimizing Critical CSS for 1C-Bitrix

Our company is engaged in the development, support and maintenance of Bitrix and Bitrix24 solutions of any complexity. From simple one-page sites to complex online stores, CRM systems with 1C and telephony integration. The experience of developers is confirmed by certificates from the vendor.
Our competencies:
Development stages
Latest works
  • image_website-b2b-advance_0.png
    B2B ADVANCE company website development
    1175
  • image_bitrix-bitrix-24-1c_fixper_448_0.png
    Website development for FIXPER company
    811
  • image_bitrix-bitrix-24-1c_development_of_an_online_appointment_booking_widget_for_a_medical_center_594_0.webp
    Development based on Bitrix, Bitrix24, 1C for the company Development of an Online Appointment Booking Widget for a Medical Center
    564
  • image_bitrix-bitrix-24-1c_mirsanbel_458_0.webp
    Development based on 1C Enterprise for MIRSANBEL
    747
  • image_crm_dolbimby_434_0.webp
    Website development on CRM Bitrix24 for DOLBIMBY
    655
  • image_crm_technotorgcomplex_453_0.webp
    Development based on Bitrix24 for the company TECHNOTORGKOMPLEKS
    976

Critical CSS Optimization for 1C-Bitrix

A typical picture: a Bitrix site loads three or four CSS files in <head> with a combined size of 300–600 KB. The browser does not begin rendering the page until it has downloaded and parsed all CSS — this is called render-blocking. As a result, FCP (First Contentful Paint) is 3–5 s on a mobile connection even with caching enabled. The solution is to extract the critical CSS (above-the-fold styles) into an inline <style> block and defer the loading of the rest.

Where Render-blocking CSS Comes From in Bitrix

Bitrix builds the CSS file list via CMain::AddCSS() and outputs it in $APPLICATION->ShowHead(). All files appear in <head> as <link rel="stylesheet"> — blocking loading by default. The main module can bundle CSS via its built-in combiner (/bitrix/cache/css/), but it does not separate critical from non-critical CSS.

Additionally: components like bitrix:catalog.section add their own styles via $APPLICATION->SetAdditionalCSS(), and component templates add styles via style.css inside the component folder. All of this ends up in the blocking path.

What Critical CSS Means in Practice

Critical CSS is the set of styles needed to render content above the fold without additional network requests. For a Bitrix site this typically includes:

  • Reset/normalize (box-sizing, base margins)
  • Header and first page block grid
  • H1, H2 heading and body text typography
  • Navigation menu styles
  • Hero banner or first slider styles

Everything else — product card styles, cart, filter form, footer — can be loaded asynchronously.

The Critical CSS Inlining Technique

Step 1: Extract Critical Styles

Use critical (Node.js) for automated extraction:

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 --width=375 --height=812. Merge the results — you get a critical.css of 15–40 KB.

Step 2: Integration into the Bitrix Template

In the template's header.php:

// Inline critical CSS
$criticalCss = file_get_contents(__DIR__ . '/critical.css');
?>
<style><?= $criticalCss ?></style>
<?php
// Async loading of remaining CSS
?>
<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 to stylesheet via onload is the standard LoadCSS pattern. <noscript> is a fallback for browsers without JavaScript.

Step 3: Working with the Bitrix CSS Combiner

If the built-in combiner is enabled (BX_COMPOSITE_BUFFER_ON_CSS), it intercepts <link> output. Either disable it for controlled files:

// In header.php before ShowHead()
define('BX_COMPOSITE_BUFFER_ON_CSS', false);

Or use the OnEndBufferContent event for post-processing HTML and replacing blocking <link> tags with asynchronous ones.

Working with PostCSS and PurgeCSS

On projects where the template is built via Gulp or Webpack, add to the pipeline:

// gulpfile.js
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-based themes this reduces CSS from 250 KB to 30–60 KB.

Case Study: Corporate Portal on Bitrix24

A company portal with ~300 employees: the home page loaded 7 CSS files with a combined size of 480 KB. FCP in Lighthouse (Desktop, Fast 3G) — 4.2 s. The goal: reduce to 1.5 s without changing the template.

What was done:

  1. Ran critical for the home page, news section, and documents section — three different critical CSS sets.
  2. Added logic in header.php to detect the page type and include the corresponding inline CSS.
  3. Migrated remaining CSS files to preload + async loading.
  4. PurgeCSS removed ~60% of unused rules from template_styles.css.

Result: FCP — 1.3 s, total above-the-fold CSS weight — 18 KB inline, the remaining 90 KB loading asynchronously after FCP.

Automating Critical CSS Updates

Critical CSS must be updated when the design changes. Embed in the deploy script:

#!/bin/bash
# post-deploy.sh
node ./scripts/generate-critical.js
php artisan cache:clear  # or bitrix/modules/main/tools/critical_css.php

The generate-critical.js script launches headless Chrome via Puppeteer, captures critical CSS from a list of key pages, and writes files to the template folder.

Diagnostics

In Chrome DevTools → Coverage (Shift+Ctrl+P → Coverage) you can see the percentage of unused CSS. A figure above 70–80% unused CSS on the first screen is a direct signal to act. In Lighthouse — the "Reduce unused CSS" metric shows potential savings in KB.

Timeline

Scale Scope Duration
Basic Manual critical CSS extraction + inline in header.php 2–3 days
Medium Automation via critical + async link loading + deploy-time update 4–6 days
Full PurgeCSS in the build, multiple critical CSS sets per page type, CI integration 7–10 days