Lazy Loading Images in Bitrix: Where Speed Breaks
Lazy loading images in Bitrix most often fails exactly where it is needed most — in catalogs and galleries. The template renders all product cards at once, the browser receives markup with hundreds of <img> tags and starts pulling them simultaneously with the first screen.
As a result, page load speed is determined not by the weight of the visible part, but by the total volume of the entire gallery, including those 40 cards the user hasn't scrolled to yet.
This is especially painful on mobile: the channel is narrow, and heavy catalog images compete for bandwidth with critical resources — styles, fonts, interface scripts.
Time to first screen grows, the user sees empty gray blocks instead of products and leaves before the images load.
At the same time, the files themselves are often not optimized: originals from 1C or supplier exports are served at full resolution, without adaptive sizes for the catalog grid.
The second typical failure point is dynamic loading.
A catalog with "show more" or infinite scroll adds new cards via AJAX, but lazy loading attributes are not applied to them: the script inserts a ready-made <img> with a direct address, and the browser immediately starts downloading all the new files. A page that initially loaded fast loses its advantage at every pagination step.
The third layer is caching and compression. Even correctly configured lazy loading won't help if the server serves images without modern formats and without proper cache headers: the browser re-downloads the same thing on every catalog navigation.
Here it's important that lazy loading is combined with adaptive versions for screen width and with a cache policy on the static delivery side.
Let's break down how this is addressed: where a component template fix is enough, where the native loading attribute is needed, and where rebuilding the gallery output and handling dynamically added cards is required.
What lazy loading delivers: measurable effects
Lazy loading changes not the "feel of the site" but specific measurable values. Let's break down exactly what shifts after implementation and how to verify it.
The first effect is the rendering speed of the first screen. The browser stops pulling all catalog images at once and requests only those that fall within the visible area.
On pages with long product lists or galleries, the time to content appearance is reduced severalfold, and the Largest Contentful Paint metric moves into the green zone. The gain is especially noticeable where a single screen previously had several dozen images.
The second effect is reduced load on the server and channel. Requests to files become fewer, the volume of data served on the first visit drops severalfold, and peak spikes during crawler traversal of the catalog stop hitting the limits.
This is not an abstract "optimization" but a direct reduction in the number of disk accesses and bandwidth per visit.
The third effect is mobile search results. For mobile devices, lazy loading works more aggressively: the user's traffic is saved, the page becomes interactive faster, and behavioral metrics — view depth and time on page — grow.
Search engines evaluate the mobile version by actual speed, and here the gain converts into rankings.
The fourth effect is that an entire class of failures disappears. Heavy pages stop timing out on a weak connection, images don't "drop off" when the connection breaks, and the server doesn't hit overload at the moment a new batch of products is published. These are the failures that used to be fixed manually after complaints.
The effect can be verified before and after: we measure rendering time, the number of requests, and the volume of traffic on a typical catalog page. The difference is recorded in a report — you see exactly what changed instead of taking our word for it.
Implementation methods: native attribute, script, module
Lazy loading in 1C-Bitrix is solved in three ways, and the choice between them is a choice between the amount of edits in the template and control over behavior.
The native loading="lazy" attribute works at the browser level: it is enough to set it in the component template or in the output settings of the infoblock property, and images below the first screen stop loading immediately.
A script gives control over the trigger threshold and source substitution, while a module provides a ready-made wrapper with caching and adaptive sets.
| Option | When it fits | Limitations |
|---|---|---|
Native loading="lazy" attribute |
Typical templates, galleries, catalog; minimal edits | No threshold control; some older browsers ignore the attribute |
| Lazy loading script | Complex markup, sliders, background images | Requires edits to the template JS and testing with JS disabled |
| Bitrix module | Many templates and content types, a unified standard is needed | Dependence on module updates, configuration for the site structure |
Browser compatibility is a key criterion: the native lazy load is supported by all current engines, but a fallback is needed for outdated ones. A script bridges this gap, however, with JavaScript disabled, images must remain visible — otherwise the page loses content.
A module solves this at the settings level, but adds a layer of abstraction between the template and the image output.
In practice, a combination also works: the native attribute as a base, a script — selectively for sliders and backgrounds, a module — when there are dozens of templates and a unified standard is needed.
We analyze the structure of the templates and choose the option to fit it, not the other way around.
Procedure for implementing lazy loading on a website
Implementation begins with an audit of the current markup: we look at how images are output in component templates, which attributes are already set, where images load in the first viewport and should not fall under lazy loading.
At this stage, we identify the points where substituting attributes will break the layout or the behavior of sliders, galleries, and lazy carousels.
- Audit of markup and templates. We go through the catalog components, detail pages, banners, and information blocks, compile a list of image output locations, and mark those that are visible immediately on opening.
- Template setup. In component templates and common include areas, we set lazy loading attributes for images outside the first viewport and define container dimensions to avoid layout shifts during loading.
- Connecting the mechanism. We configure the core's built-in tools and connect a handler that loads the image as it approaches the viewport, with a margin for the distance before it appears on screen.
- Exceptions and priorities. We exclude the logo, the main banner, and first-viewport images from lazy loading — they must load immediately, otherwise the page "flickers" and loses rendering speed.
- Testing on devices. We check behavior on mobile, tablets, and desktop, in different browsers, on a slow connection, and with JavaScript disabled — content must remain accessible.
- Measurements before and after. We compare the volume of loaded data and the time to first-viewport render, and record the result for key templates.
- Support regulations. We hand over a document: which templates are affected, how to add new images, what to check when outputting new blocks, so that lazy loading is not disabled by accidental edits.
After the regulations are handed over, new pages and blocks are output according to the already configured rules — the support team does not break the mechanism when editing content, and loading speed remains stable.
Policies and configuration: what we lock down in templates
Lazy loading does not live separately from the template: if the markup and attributes are not locked down in the code, the very first redesign or new catalog card will bring heavy <img> tags back into the first screen.
That is why we move agreements from "word of mouth" into artifacts that both the developer and the content manager can see.
What we lock down in component templates
Edits go into component templates, not the core — platform updates do not overwrite them.
For each image output location we define the behavior explicitly: the first-screen cover loads immediately, everything below loads as it enters the viewport, with reserved dimensions so the layout does not "jump".
- Modified component templates: lazy loading attributes, container dimensions, sets for different screen widths.
- Rules for the media library: which sizes are generated on upload, which formats are considered primary, what to do with source files.
- Caching settings: lifetime of the template and component cache, reset when bound elements change, so that an image edit lands on the page immediately.
- Image compression policy: compression level and output formats, uniform across the entire catalog and content.
- Priority scheme: what loads first, what is deferred, what is loaded only when scrolling to the block.
- Instructions for content managers: how to upload images so that the rules do not break at the content-filling stage.
How this relates to caching
Lazy loading and cache conflict if configured separately: an aggressive cache serves stale markup, while clearing "just in case" kills the speed gain. We set up tagged reset — when an element changes, only the related cache is invalidated, while other pages stay warm.
This way the content manager changes an image and immediately sees the result, and the visitor does not wait for the page to be rebuilt.
Where we apply this
We describe the rules for the 1C-Bitrix platform and its Bitrix24 edition, taking into account how information blocks and the media library are structured in the project.
The result is a set of configurations and instructions that the customer's team can use to keep adding pages without returning to the speed question every time.
Case study: speeding up an online store catalog
A catalog with 800+ items, filters, and pagination loaded its first page in 6-7 seconds on an average mobile connection.
The problem was not the server: the page returned its markup quickly, but the browser was synchronously pulling all product previews, including those far outside the viewport.
On mobile this produced the worst-case scenario — the user saw a white screen, did not wait, and left, and in analytics this settled as bounces that are impossible to distinguish from "didn't find what they needed."
What was measured before implementation
We captured baseline metrics across three scenarios: a cold entry into the catalog, navigating by filter, and scrolling through pagination.
We recorded the time until the first content appeared, the time until full render, and the share of sessions that ended before the first scroll.
Separately, we measured the weight of the first page — it was many times larger than what is needed for the visible area, because loading happened in a single stream together with the markup.
What was changed
We implemented lazy loading of images at the level of the catalog component template: previews outside the viewport receive their source only when they approach the visible area, with a margin of one or two screens so there are no jolts during fast scrolling.
For browsers without native support, we kept a fallback mechanism via observing the element's position, and the images themselves were converted to modern formats with a fallback option.
At the same time, we fixed the container dimensions so the markup would not "jump" when images were substituted in.
Metrics after
The first content on mobile began appearing 2.5-3 times faster, and the full render of the first page fit within a range at which the user does not have time to leave. The initial load weight shrank by roughly three times — only what is actually visible gets loaded.
The share of bounces before the first scroll dropped noticeably, and catalog view depth grew: people started scrolling through to the second and third pages, which almost never happened before.
The project was led by our integration engineer 1C-Bitrix — the edits touched only the output template and did not affect the product selection logic, so catalog updates and prices continued to sync as usual.
How does native lazy load differ from script-based?
The native lazy-loading mechanism is the loading="lazy" attribute on the <img> tag, which the browser itself handles.
It requires no libraries, does not block the main thread, and adds no initialization requests: the engine itself decides when an element approaches the viewport and loads the resource.
The script-based variant is an external library or custom code based on intersection observers that intercepts loading by swapping src for data-src and triggers the substitution manually.
The difference in behavior shows up in edge-case scenarios. The native mechanism works correctly with JavaScript disabled, when printing a page, and in reading mode — images will still render.
The script-based one depends on code execution: if the script fails to load, crashes on an error, or is blocked by a security policy, the user will see empty frames.
On the other hand, a script provides controllable trigger thresholds, click-to-load, adaptive sets for different screens, and appearance animation — things the native attribute cannot do.
Browser support for the native mechanism is broad, but not absolute: older engines ignore the attribute and load everything at once, which is safe but provides no benefit.
The script-based variant works the same everywhere JavaScript executes — that is its main advantage on a legacy fleet of devices.
For indexing, the difference is fundamental. Search engine robots do not always execute JavaScript and not instantly, and some social media crawlers do not run it at all.
With the script-based approach, the source code contains data-src rather than src — the robot may not see the image address and may not associate it with the page.
The native attribute leaves the real src in the markup, so the image is indexed as usual, and the deferral applies only to the moment of loading. For galleries, catalogs, and product cards, this directly affects whether they appear in image search.
The practical takeaway: the native mechanism is the baseline layer for content images, while the script-based one is for cases where thresholds, adaptivity, and animation are needed.
A mixed scheme covers both requirements: the markup remains readable for robots, and the behavior remains controllable.
Common technical concerns when implementing
Lazy loading in 1C-Bitrix is almost always implemented on top of an already working template, so the customer's first questions are not "how to enable it" but "what will break." Below is an analysis of the technical concerns that most often come up during the evaluation stage.
Is this compatible with the current template and components?
Yes, if the loading="lazy" and decoding="async" attributes are added to <img> tags at the output level, rather than by manually editing the markup.
In Bitrix this is done by processing the results of components, news and catalog templates: the script goes through the finished HTML and adds the attributes without changing the DOM structure.
Custom sliders, galleries, and lazy carousels are excluded from processing — they have their own loading logic, and interference breaks switching.
The first screen (banner, logo, key product image) is forced to remain with loading="eager", otherwise the time to render the main content increases.
Will search results suffer?
No, with correct markup. Search engine robots execute JavaScript and load deferred images during crawling, and the loading attribute is a standard signal for them, not content hiding.
The risk arises in one scenario: if images are inserted by a script without src in the original HTML, the robot may not see them in the markup.
That is why we keep the real src and only add the lazy loading attribute — the image remains in the document, only the moment the file is requested changes.
How are changes rolled back and what about the browser cache?
Edits are made as a separate module or handler, not scattered across templates — a rollback comes down to disabling a single connection, without restoring files from a backup.
The browser cache does not get in the way: the attributes are served in the HTML, not in static files, so after resetting the Bitrix composite cache the changes are visible immediately.
If composite mode is used, we warm the cache again — otherwise some pages will serve the old markup.
Let's discuss your website speed optimization task
Describe the current situation: which section is slow, how many images are on the page, how the markup is structured, and where the images come from — the media library, information blocks, or external storage.
This is enough for us to come back with a scope estimate and an implementation plan for lazy loading images in Bitrix, without vague wording or "universal" advice.
Here is what we will analyze and include in the plan:
- the current page load profile: which images load immediately, how many there are, and what share lands above the fold;
- the approach for connecting lazy loading — through component settings, the template, or a separate script, with a fallback for older browsers;
- behavior when JavaScript is disabled and for search engine bots, so images remain indexed;
- generation and caching of resized copies, so delivery does not hit the original file size limit;
- compatibility with current templates, sliders, galleries, and caching modules;
- the rollout order: first a test environment, then gradually to the production site with the ability to roll back quickly;
- the website support procedure after implementation — who monitors new images and settings, and how.
For each item, we will provide a clear estimate: what we do, in what order, and what we check at the output. Describe your task — we will come back with a plan and timelines.

