Optimizing LCP (Largest Contentful Paint) 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

Optimizing LCP (Largest Contentful Paint) for 1C-Bitrix

LCP is the time to display the largest visible element on the page. Google considers good LCP < 2.5 seconds. Bitrix sites typically show 4–10 seconds, directly impacting search ranking and conversion.

What is an LCP Element

Browser determines LCP element automatically — it's the largest content by area in viewport on first load. In Bitrix store, typically:

  • Hero banner/slider on homepage
  • First product image on category page
  • Hero image on landing page

Check: Chrome DevTools → Performance → record trace → in Timings section find LCP marker, click — DevTools shows the specific element.

Why LCP is Poor: Dependency Chain

Typical chain for banner in Bitrix slider:

  1. Browser requests HTML → waits for TTFB (500 ms – 2 s)
  2. HTML parsed → finds <script src="swiper.min.js"> in <head> — blocks parsing
  3. Swiper.js loads (200 KB), parsed, executed
  4. JS initializes slider, creates <img> in DOM
  5. Browser detects image → starts loading
  6. Image loads (PNG/JPEG, 500 KB – 2 MB)
  7. LCP registered

On poor 3G, this is 8–12 seconds. Each step can be optimized.

Fixing TTFB as LCP Base

LCP can't be less than TTFB — until server delivers HTML, browser can't work. TTFB optimization via SQL indexes, component cache, OPcache is first step. See TTFB optimization article.

Goal: TTFB < 200 ms for cached pages.

Preload LCP Image

Most effective action — tell browser about LCP image before parsing HTML body:

<!-- Add to <head> BEFORE all scripts and styles -->
<link rel="preload" as="image"
      href="/upload/resize_cache/iblock/banner_main.webp"
      fetchpriority="high"
      imagesrcset="/upload/resize_cache/iblock/banner_main_800.webp 800w,
                   /upload/resize_cache/iblock/banner_main_1600.webp 1600w"
      imagesizes="100vw">

In Bitrix, add via AddHeadString() at template start or directly in header.php:

// In component_epilog.php or header.php
if ($arResult['BANNER_IMAGE']) {
    $GLOBALS['APPLICATION']->AddHeadString(
        '<link rel="preload" as="image" href="' . $arResult['BANNER_IMAGE'] . '" fetchpriority="high">',
        true  // true = add to head start
    );
}

fetchpriority="high" tells browser to load this resource with highest priority, ahead of other images.

Static First Slide Instead of JS Initialization

Hero banner in Bitrix often implemented as JS slider. Problem: JS initializes slider after loading and executing script — image appears with delay.

Solution: render first slide in static HTML, JS slider initialization for subsequent interaction:

// In template.php of main banner component
$firstSlide = $arResult['ITEMS'][0];
?>
<!-- Static first slide — browser sees immediately -->
<div class="banner-slider" id="main-banner">
    <div class="swiper-slide swiper-slide-active">
        <img src="<?= $firstSlide['IMG']['SRC'] ?>"
             width="<?= $firstSlide['IMG']['WIDTH'] ?>"
             height="<?= $firstSlide['IMG']['HEIGHT'] ?>"
             fetchpriority="high"
             alt="<?= htmlspecialchars($firstSlide['NAME']) ?>">
    </div>
</div>

<!-- JS initializes after page load -->
<script defer>
document.addEventListener('DOMContentLoaded', function() {
    new Swiper('#main-banner', { /* ... */ });
});
</script>

Image Optimization

Format. WebP is 25–35% smaller than JPEG at same visual quality. AVIF is 20–30% smaller but browser support slightly worse.

Bitrix can serve WebP via \Bitrix\Main\File\Image::resize() when enabled in .settings.php. AVIF support requires ImageMagick with AVIF support or external service.

Size. Image 3000×2000 px for banner on 1920px screen is triple waste. Set sizes via CIBlock::GetPreviewPicture() or \Bitrix\Main\File\Image::resize():

$resizedImage = \CFile::ResizeImageGet(
    $originalFileId,
    ['width' => 1920, 'height' => 600],
    BX_RESIZE_IMAGE_PROPORTIONAL_ALT,
    false,
    false,
    false,
    90  // quality
);

Compression. Additional optimization via mozjpeg or oxipng at server level: lossless quality, 15–20% size reduction. Configured via nginx ngx_http_image_filter_module or external optimizer on file upload via OnFileSave event handler.

Responsive Images Recommendations

Mobile user with 375px screen shouldn't download 1920px banner. Use srcset:

<img src="/upload/banners/banner_1200.webp"
     srcset="/upload/banners/banner_480.webp 480w,
             /upload/banners/banner_800.webp 800w,
             /upload/banners/banner_1200.webp 1200w,
             /upload/banners/banner_1920.webp 1920w"
     sizes="100vw"
     width="1920" height="600"
     fetchpriority="high"
     alt="Hero banner">

In Bitrix template: pre-slice multiple sizes via CFile::ResizeImageGet() and output in srcset.

LCP Optimization Timeline

Task Time LCP Improvement
Preload main image 0.5 day −0.5–1 s
Static first slide without JS dependency 1–2 days −1–2 s
WebP conversion + resize 1 day −0.5–1.5 s
TTFB optimization 3–10 days −1–3 s
Defer/async for non-critical scripts 1 day −0.3–0.8 s
Responsive images + srcset 1–2 days −0.5–1 s

With comprehensive work, realistic goal: LCP < 2.5 s for mobile, < 1.5 s for desktop on cached pages.