CSS and JS Bundling in 1C-Bitrix: Speed Up Loading
We often take over projects that have evolved over years and discover chaos in CSS and JS management. A typical scenario: 60–120 requests for styles and scripts on a catalog page. Even with HTTP/2, each additional request consumes time for DNS, TCP, and TLS. On mobile networks, this kills performance. Our experience shows that combining files can reduce the number of requests by 10–20 times and speed up loading by 40–70%.
Why Bundling CSS and JS Speeds Up the Site?
Browsers limit the number of concurrent connections to a single domain (typically 6). When there are many files, they load sequentially. Bundling into one file reduces the number of requests, which is particularly noticeable on mobile networks. It also lowers the overhead for DNS, TCP, and TLS per request. For more details, see HTTP/2.
Bitrix's Built-In Bundling Mechanism
Bitrix offers two approaches: using the asset management API and the bitrix:main.include component. When minification is enabled (Settings → Performance → Compression), all registered CSS files are collected into /bitrix/cache/css/<hash>.css and JS into /bitrix/cache/js/<hash>.js. However, only files registered before ShowHead() are bundled. Direct <link> tags in templates are ignored.
What Problems Do We Solve?
Order of inclusion. When bundling, the CSS cascade often breaks. For example, reset styles must come first, component styles later. The solution is to use \Bitrix\Main\Page\Asset::addCss() with explicit dependency specifications or split into two bundles: base (grid, typography) and dynamic (widgets).
Inline styles and scripts. Many components (e.g., bitrix:news.list) output render directly into HTML. This is not bundled. For custom solutions, we replace echo '<style>' with $this->addExternalCSS() so that the file goes into the common bundle and is cached.
Duplicates and version conflicts. On one project, we found 12 identical normalize.css files and three versions of jQuery (1.9, 2.1, 3.6) on a single page. Auditing by intercepting AddCSSLink() and logging helped unify libraries. Tree shaking and code splitting are the next steps.
How We Do It: Vite and Webpack
For modern projects, Bitrix's built-in tools are insufficient. We use Vite or Webpack.
Example structure with Vite:
local/templates/mytemplate/
├── src/
│ ├── css/
│ │ ├── main.scss
│ │ └── components/
│ ├── js/
│ │ ├── app.js
│ │ └── pages/
├── dist/ ← Vite builds here
│ ├── app.[hash].css
│ └── app.[hash].js
├── header.php ← includes dist/
└── vite.config.js
In header.php, we include the bundles via CMain::AddCSSLink() so they are cached by Bitrix. Vite provides HMR during development and tree shaking for production.
Why Vite Is Better Than the Built-In Mechanism
Vite supports SCSS, TypeScript, and automatic code splitting. Bitrix's built-in bundling does not. In practice, we achieve a bundle size reduction of 30–50% by removing dead code. Comparison:
| Characteristic |
Built-in Mechanism |
Vite/Webpack |
| SCSS support |
No |
Yes |
| Code splitting |
No |
Yes |
| Tree shaking |
No |
Yes |
| HMR |
No |
Yes |
| Configuration |
Simple |
Requires config |
Case Study: Portal with Three Developer Teams
One of our clients is a B2B portal, 5 years in development, with three teams that have come and gone. On the catalog page: 47 CSS requests (890 KB uncompressed), 68 JS requests (1.4 MB). Our audit revealed: 12 CSS duplicates, 8 JavaScript libraries in multiple versions.
What we did:
- Audited all inclusions by intercepting
CMain::AddCSSLink() and AddHeadScript() with logging.
- Unified libraries: single jQuery version, removed duplicates.
- Migrated all direct
<link> tags to the Bitrix API.
- Set up Vite for new code, packaged legacy code into a single bundle.
- Code splitting: critical bundle + 4 page-specific bundles.
Result:
- 47 CSS requests → 3.
- 68 JS requests → 5.
- Total CSS+JS weight (after gzip) dropped from 850 KB to 210 KB due to duplicate removal and tree shaking.
- Page load speed improved from 4.2 s to 1.1 s (Lighthouse).
Process of Work:
- Analytics — collect logs of all inclusions, identify duplicates, conflicts, dead code.
- Design — define bundle architecture: critical, page-specific, deferred.
- Implementation — migrate inclusions to API, set up builder (Vite/Webpack), write configurations.
- Testing — verify every page for correct display and JS functionality.
- Deployment — upload to production, check caching.
Bitrix's tagged caching invalidates cache when data changes. When bundling files, it is important that CSS/JS cache invalidation works correctly. We configure this via $arParams["CACHE_TAGS"].
What Is Included in the Work:
- Full audit of current inclusions with a report.
- Library unification and duplicate removal.
- Setup of the builder (Vite or Webpack) for your template.
- Integration with Bitrix tagged caching.
- Documentation on the build process and inclusion.
- Team training on the new architecture.
- One week of post-release support.
Timelines
| Project Type |
Scope of Work |
Timeline |
| Simple site (1 template, <30 components) |
Migrate inclusions to API, enable minification |
1–2 days |
| Medium project (custom frontend, multiple templates) |
Audit + library unification + build setup |
3–7 days |
| Large portal (multiple teams, legacy code) |
Full audit, refactor inclusions, set up Webpack/Vite |
7–20 days |
Cost is determined individually after the audit. Contact us for a consultation — we will propose the optimal solution. We guarantee at least a 2x loading speed improvement, confirmed by tests.
Load testing after bundling is mandatory — in rare cases, the loading sequence of scripts matters, and breaking it can cause JS errors on specific pages. Our experience allows us to anticipate such nuances and avoid them at the design stage. Get a consultation and optimization plan.
Why does website layout for 1C-Bitrix require professionalism?
Open template.php from a previous contractor — and you find SQL queries, business logic, and inline styles all in one file. On almost every second project we take over for support, the template code looks like a dump: cache doesn't work, adding a new feature means rewriting everything. Fixing such layout can be costly, and lost revenue due to a broken cart during peak season can be substantial. Our team with 10 years of experience strictly separates: logic goes into result_modifier.php or component_epilog.php, presentation into template.php. No CIBlockElement::GetList in templates. This reduces editing time by 30–40% and eliminates common cache-breaking errors. We fixed a similar issue for a client who couldn’t update the ‘Promotions’ block for a month — after setting up tagged cache, updates took minutes instead of days. Want the same results? Get a free audit of your current layout.
How to properly organize component templates?
A custom template is not a single file but a structure of five to six files:
-
template.php — only HTML and output of $arResult
-
result_modifier.php — data preparation, additional queries
-
component_epilog.php — code after caching (counters, dynamic content)
-
style.css and script.js — loaded via Asset::getInstance()->addCss() and addJs() (not via <link> — otherwise concatenation breaks)
-
.parameters.php — visual editor parameters
Example structure for a catalog:
local/templates/your_template/components/bitrix/catalog.section/.default/
├── template.php
├── result_modifier.php
├── component_epilog.php
├── style.css
├── script.js
└── .parameters.php
Typical templates we develop turnkey:
| Component |
What we do |
catalog.section and catalog.element |
View switching (grid/list/table), lazy load for images, srcset for retina |
sale.basket.basket |
AJAX update without reload, mini-cart via sale.basket.basket.line |
menu |
Mega menu with caching by sections, lazy loading of submenus |
search.title |
Autosuggest with 300ms debounce, product previews in dropdown |
breadcrumb |
Microdata BreadcrumbList according to Schema.org |
Caching: why does it break and how do we fix it?
Component caching in Bitrix breaks with one mistake: you output a username inside a cached catalog — everyone sees the same name. Solution — use component_epilog.php for dynamic inserts.
Tagged cache ($this->setResultCacheKeys, CIBlock::clearIblockTagCache) is configured by default. Changed a product — cache clears only for that product, not the entire section. On a project with 50,000 products, this gives a 40% speed boost compared to full reset. Official Bitrix documentation recommends using component_epilog.php for dynamic inserts. Real case. A client complained that everyone saw the same cart on the catalog page. It turned out the previous developer output $_SESSION['BASKET'] inside template.php of the catalog.section component. The component was cached for an hour — the cart was frozen. We moved the output to component_epilog.php and configured tagged cache on sale.basket.basket.line. The page didn’t lose speed, the cart became up-to-date. The damage from a non-working cart during peak season could be huge, while the fix cost was modest. Tagged cache reduces page rebuild time by 50× compared to full reset.
CSS approaches: BEM, Tailwind, or hybrid?
For large projects (30+ templates) we use BEM — .product-card__price, .product-card--featured. Styles are isolated, no conflicts. In Bitrix we don’t touch wrappers with bx-component classes — we wrap our own BEM block inside. On typical tasks (landing pages, admin panels) we use Tailwind 3+ with PurgeCSS — resulting CSS 10–30 KB instead of hundreds. Design tokens in tailwind.config.js lock colors, fonts, spacing in one place. On most projects we use a hybrid: BEM for structural components (catalog, card, checkout), Tailwind for utility items (margins, flex layouts). We agree on the boundary with the team in advance.
How do we achieve Core Web Vitals?
Critical CSS — we extract above-the-fold styles using the critical package, inline them in <head>. The rest loads asynchronously via media="print" onload="this.media='all'". LCP on mobile decreases by 1–1.5 seconds.
Images — the main bottleneck. We use <picture> with WebP and JPEG fallback. loading="lazy" for everything below the fold. width and height explicitly set — CLS = 0. A handler in urlrewrite.php generates WebP on the fly.
Minification and compression. CSS and JS via Vite or Bitrix built-in concatenation. Brotli on nginx (brotli_comp_level 6) — 15–20% more efficient than gzip. Static caching: expires 1y + versioning via query string.
For a catalog of 10,000 products, LCP went from 4.2 s to 2.1 s. Conversions improved by 12% after the speed fix. Want similar results? Order a free audit — we’ll evaluate your current layout and propose specific steps.
Deliverables after layout completion
When you order template development or adaptation, you receive:
- Source files of component templates with separation into
template.php, result_modifier.php, epilog
- CSS and JS loaded via Asset — no inline styles
- Configured caching with tags
- Documentation on structure and parameters
- Access to a Git repository with change history
- Training for your developer: how to edit the template without losing upgradeability
We guarantee Core Web Vitals compliance and cross-browser compatibility. Each project is assigned a lead engineer with 10+ years of Bitrix experience.
Process:
- Analysis of mockups and current project — identify components for rework
- Structure design — break the page into BEM blocks
- Implementation — build templates according to the scheme: template, result_modifier, epilog, CSS, JS
- Testing — check cache, responsiveness, Core Web Vitals, cross-browser compatibility
- Deployment — staging, acceptance, production
At each stage you get intermediate results and can make corrections. Contact our team for a project estimate — we’ll provide a timeline and cost within 1–2 days after receiving mockups.
Common mistakes in Bitrix layout
- SQL queries inside
template.php — breaks caching and creates heavy load
- Inline
<style> and <script> — breaks Asset concatenation and slows loading
- Missing
result_modifier.php — logic mixed with presentation
- Direct
$_REQUEST in cached components — user-specific data leaks
- Not using
component_epilog.php for dynamic content — entire cache invalidated on each user action
Each mistake has a simple fix — we correct them during development or audit.
Timelines
| Scope |
Timeline |
| Landing page (5–7 screens) |
3–5 days |
| Corporate website (15–20 unique pages) |
2–4 weeks |
| E-commerce store (30+ component templates) |
4–8 weeks |
| Customization of a Marketplace solution |
1–3 weeks |
| Redesign of an existing project |
3–6 weeks |
Ready to improve your layout? Order a preliminary consultation — we’ll calculate timelines and budget individually.