Setting up lazy loading of images in 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
    1177
  • 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

Lazy Loading Configuration for 1C-Bitrix

On a catalog page with 48 product cards, the browser by default loads all 48 images when the page opens — including those outside the visible viewport. With an average product image weight of 80–150 KB, this amounts to 4–7 MB of unnecessary traffic on the first load, which slows down Largest Contentful Paint and Time to Interactive.

Native Lazy Loading

The most modern and simplest approach is the loading="lazy" attribute on <img> tags. Browsers from Chrome 77, Firefox 75, and Safari 15.4 onwards support it natively:

<img src="/upload/product.jpg" loading="lazy" width="300" height="300" alt="...">

The width and height attributes are required — without them the browser cannot reserve space for the image before it loads, which causes layout shift (the CLS metric).

In Bitrix component templates, this is added to the template.php of the catalog.element and catalog.section components:

<img src="<?= $item['PREVIEW_PICTURE']['SRC'] ?>"
     loading="lazy"
     width="<?= $item['PREVIEW_PICTURE']['WIDTH'] ?>"
     height="<?= $item['PREVIEW_PICTURE']['HEIGHT'] ?>"
     alt="<?= htmlspecialchars($item['NAME']) ?>">

For above-the-fold images (hero, first 2–4 cards in the grid), loading="lazy" should not be used — it would delay their loading and worsen LCP.

JavaScript Implementation for Older Browsers and Custom Scenarios

If support for Safari prior to 15.4 is needed, or non-standard behavior is required (e.g., a preloader during loading), use IntersectionObserver:

const lazyImages = document.querySelectorAll('img[data-src]');
const observer = new IntersectionObserver((entries) => {
    entries.forEach(entry => {
        if (entry.isIntersecting) {
            const img = entry.target;
            img.src = img.dataset.src;
            img.removeAttribute('data-src');
            observer.unobserve(img);
        }
    });
}, { rootMargin: '200px' });

lazyImages.forEach(img => observer.observe(img));

rootMargin: '200px' — the image starts loading 200px before it enters the viewport. This prevents flickering during fast scrolling.

Lazy Loading for CSS Background Images

CSS background images (the background-image property) are not supported by native lazy loading. The solution is to add a loaded class via IntersectionObserver and only define the background for elements with that class:

.banner { background-color: #f0f0f0; } /* placeholder */
.banner.loaded { background-image: url('/upload/banner.jpg'); }

Case Study and Results

An online store with a catalog page displaying 60 products (3 columns × 20 rows, most below the fold). After adding loading="lazy" to all cards except the first row: the volume of images loaded on the first visit dropped from 6.2 MB to 1.1 MB. LCP decreased from 3.8 s to 1.9 s. During scrolling, users notice no delay — images load in advance thanks to rootMargin.

Setting up lazy loading takes 4–8 hours: auditing component templates, adding attributes, testing on real devices (it is important to verify the absence of CLS on mobile). Projects with SSR or non-standard sliders will require additional configuration for specific components.