Font optimization 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

Font Optimization for 1C-Bitrix

Fonts are one of the most underestimated sources of page load delay. A typical Bitrix project has this situation: the site loads 4–6 Google Fonts weights via @import directly in CSS, each @import blocks rendering, the browser waits for the CSSOM, and the user sees a blank page or the "Flash of Invisible Text" (FOIT). Lighthouse flags this as "Ensure text remains visible during webfont load" and directly harms the LCP metric.

How Bitrix Loads Fonts by Default

In most themes, fonts are loaded in one of three ways:

  1. @import url('https://fonts.googleapis.com/...') inside template_styles.css — the slowest option: the browser discovers the request only after downloading CSS.
  2. A <link> in the template's header.php without preconnect and preload attributes.
  3. Direct loading of .woff/.woff2 files via CDN without caching headers.

Bitrix does not manage fonts through the core — everything lives in the template, so changes must be made there, not through the main module settings.

Key Optimization Techniques

Self-hosted Fonts Instead of Google Fonts

Loading fonts from an external CDN adds a DNS lookup + TCP handshake + TLS negotiation — totaling 100 to 300 ms on a cold connection. Move fonts to your own server:

# Download via google-webfonts-helper or npx
npx google-webfonts-helper --family="Roboto" --subsets="latin,cyrillic" --variants="400,700"

Place files in /local/templates/[template]/fonts/, CSS in fonts.css:

@font-face {
    font-family: 'Roboto';
    src: url('/local/templates/main/fonts/roboto-400.woff2') format('woff2');
    font-weight: 400;
    font-style: normal;
    font-display: swap;
    unicode-range: U+0400-045F, U+0490-0491; /* Cyrillic only */
}

font-display: swap is mandatory. Without it, the browser blocks text rendering until the font is loaded.

Preload for Critical Weights

Add preload in the template's header.php for the weight used on the first screen:

// header.php
$APPLICATION->AddHeadString(
    '<link rel="preload" href="/local/templates/main/fonts/roboto-400.woff2" as="font" type="font/woff2" crossorigin="anonymous">'
);

Preload works for one or two weights. Preloading all variants is counterproductive: the browser downloads them with high priority, competing with HTML and critical CSS.

Subsetting: Removing Unnecessary Glyphs

The full Roboto font weighs 150–200 KB per weight. For a site in English or any single-script language, only the latin subset is needed. For multilingual sites include only the required Unicode ranges. Using pyftsubset (fonttools):

pyftsubset roboto-regular.ttf \
    --unicodes="U+0020-007E,U+0400-045F,U+0490-0491,U+00A0" \
    --flavor=woff2 \
    --output-file=roboto-400-subset.woff2

Result — a file of 20–35 KB instead of the original 150+ KB.

Variable Fonts

If the design uses multiple weights of the same typeface (Regular, Medium, Bold), consider a variable font — one file replaces several:

@font-face {
    font-family: 'Roboto';
    src: url('/fonts/Roboto-VF.woff2') format('woff2 supports variations'),
         url('/fonts/Roboto-VF.woff2') format('woff2');
    font-weight: 100 900;
    font-display: swap;
}

The Roboto variable font weighs ~75 KB and covers all weights — versus 4×30 KB = 120 KB for individual subset files.

Case Study: Building Materials Online Store

A store on Bitrix "Business" loaded 3 font families via Google Fonts: Roboto (3 weights), Open Sans (2), Oswald (1). That's 6 HTTP requests to fonts.googleapis.com + 6 requests to fonts.gstatic.com. The render-blocking delay was 480–620 ms, LCP on mobile — 4.8 s.

After migrating to self-hosted with subsetting and a single preload for Roboto 400:

  • LCP dropped to 2.1 s
  • Total font weight: from 820 KB to 94 KB
  • Render-blocking from fonts: 0 ms (thanks to font-display: swap + preload)

The work took 2 days: analyzing the current setup, preparing subset files, editing header.php and fonts.css, testing in Lighthouse and WebPageTest.

Diagnosing Issues

Quick check via DevTools: Network → Font tab. If the Initiator column says stylesheet (not preload), the font is loading reactively, not proactively. Achieving an FCP in Lighthouse below 1.8 s with render-blocking fonts present is practically impossible without the optimizations described above.

Timeline

Scale Scope Duration
Basic Self-hosted + font-display: swap + preload 1–2 days
Full Subsetting, variable fonts, audit of all templates, caching headers setup 3–5 days