↩️ Назад

Категории

65 → 95 в PageSpeed: разбор ускорения сайта на Битриксе

23.10.2026 | из категории: Web-разработка

Как ускорить сайт на битрикс до 95 в PageSpeed

Главная страница сети логопедических центров весила 895 КБ, а самая крупная картинка появлялась только на пятой секунде. Ниже — что именно мы делали, в каком порядке, что это дало в цифрах и что не получилось. Всё проверялось замерами, а не на глаз.

65 → 95балл производительности, телефон
895 → 504 КБвес главной страницы
5,8 → 3,3 сLCP, появление главной картинки
1/3 → 3/3агентный просмотр
32 → 89страница с видео и чатом

01Задача и как мы мерили

На телефоне PageSpeed показывал 65, на компьютере — 98. То есть сайт «нормальный», но на телефоне посетитель ждёт картинку пять секунд. Отчёт называл три виновника: вес, блокирующие отрисовку файлы и чужие скрипты.

ПоказательДоПосле
Балл, телефон6595
Балл, компьютер98100
Вес страницы895 КБ504 КБ
Первая отрисовка (FCP)2,0 с1,3 с
Главная картинка (LCP)5,8 с3,3 с
Задержка отклика (TBT)470 мс120 мс
Доступность8496

Почему одного прогона мало

Пять прогонов подряд на одном и том же состоянии дали 60, 82, 87, 88, 88. Один прогон, где ядро сайта случайно успело выполниться уже после первой отрисовки, роняет TBT с 90 до 950 мс — и балл с 88 до 60. Поэтому сравнивать надо медиану трёх-пяти замеров, иначе будешь гоняться за случайностью.

важно

Мой локальный Lighthouse показывал 65 там, где встроенный отчёт Google у владельца показывал те же 65, а после правок — 88 против 95 в отчёте Google. Условия симуляции у инструментов разные. Ориентироваться надо на список пунктов в отчёте, а спорить об абсолютном балле бессмысленно.

02Кэш, которого не было

Самая дорогая находка оказалась скучной: сервер не говорил браузеру, сколько можно хранить картинки формата webp и шрифты. Каждый заход — заново.

В отчёте это выглядело как 384 КБ «на выброс» из 895. Правило в .htaccess закрывало jpeg, png, css и js, а webp, woff и woff2 в нём просто не были перечислены.

# было: три дня и только для части типов
ExpiresByType image/jpeg "access plus 3 day"
ExpiresByType text/css  "access plus 3 day"

# стало: год и для того, что реально отдаётся
ExpiresByType image/webp "access plus 1 year"
ExpiresByType font/woff2 "access plus 1 year"
ExpiresByType font/woff  "access plus 1 year"
грабля

Проверять надо каждый файл из отчёта отдельным запросом. У этого сайта css, js и svg отдаёт не Apache, а nginx, и правила из .htaccess к ним не применяются вообще: они уже шли с трёхдневным сроком, прописанным в конфиге хостинга. То есть половина пункта «кэш» из файла на диске не лечится — нужна панель хостинга или письмо в поддержку.

03Логотип на 349 КБ, который показывается тридцатью пикселями

Вес страницы складывается не только из фотографий. Здесь самый тяжёлый файл на главной — значок мессенджера.

max-logo.svg весил 349 КБ. Внутри SVG лежала зашитая растровая картинка 1000×1000 (253 КБ в base64), а показывался этот значок в шапке, подвале и блоке контактов размером около тридцати пикселей.

Один и тот же файл до и после пересборки:
было349 КБ
стало14,5 КБ

Картинку внутри ужали до 128×128 и вложили обратно в тот же файл. Затем отрисовали старую и новую версию в браузере и сравнили попиксельно: средняя разница 0,1 из 255, максимальная — 2. Это уровень «не видно даже при увеличении».

проверено

Расширение файла ничего не говорит о его весе. Смотреть надо внутрь: SVG с вложенным растром весит как фотография, а рисуется как иконка.

04Bootstrap: 195 КБ → 76 КБ, и как я на этом сломал меню

Треть отчёта — «неиспользуемый CSS». Из библиотеки Bootstrap на сайте работала примерно десятая часть правил.

Порядок такой: обойти сайт по ссылкам (не только по карте сайта — карта отдавала 119 адресов, обход нашёл 128) и собрать все классы, которые реально встречаются в разметке. Вышло 452 класса из почти двух тысяч. Затем вырезать правила, где нет ни одного живого класса — но чужие правила с элементом вместо класса (html, h1, *) оставлять всегда.

Первая сборка получилась 38 КБ вместо 195 — и меню на телефоне перестало открываться.

грабля

Вырезая «неиспользуемые» классы, я вырезал правила компонентов, которыми управляет скрипт: у панели меню классы offcanvas и offcanvas-end в разметке есть, а show и showing дописывает библиотека на лету — их в разметке нет, и они попали под нож. Внешне это выглядит так: скрипт класс добавляет, а панель остаётся за правым краем экрана со сдвигом 400 px. Ошибок в консоли при этом ноль.

Починка — не косметическая, а по смыслу: правила всех компонентов, которыми управляет скрипт (меню, модальные окна, выпадающие списки, аккордеоны, слайдеры, всплывающие подсказки), больше не вырезаются вообще. Файл вырос с 38 до 76 КБ — это 12,3 КБ в сжатом виде против 27,2 КБ исходных.

Что проверяли кликомРезультат
Меню на телефоне, 390 pxоткрывается, 20 ссылок
Вложенный пункт внутри менюраскрывается
Выпадающее меню «Наши центры»открывается
Аккордеон на странице ценраскрывается
Геометрия страницы против исходной799 элементов, 0 расхождений
цена решения

Урезанный набор стилей становится хрупким: если завтра понадобится новый класс Bootstrap, его придётся дописывать вручную. Оригинальный файл лежит рядом, откат — одна строка в шаблоне.

05Шрифты: 94 КБ → 57 КБ без потери вида

Два фирменных шрифта весили почти сто килобайт и грузились первыми, потому что ими набраны заголовки первого экрана.

В них были все символы, которые поддерживает шрифт, — включая те, которых на сайте нет никогда. Мы собрали все 180 разных символов, встречающихся в текстах всех страниц, добавили страховку (латиница целиком, вся основная кириллица, типографика) и вырезали остальное.

Вес двух шрифтов:
было94 КБ
стало57 КБ

Проверка двойная: во-первых, сверили таблицу символов — ни один символ, который был в исходном шрифте, не пропал. Во-вторых, сняли страницу до и после: начертание то же, потому что контуры букв не менялись, вырезаны только лишние знаки.

проверено

Шрифт — это то, что видно всем посетителям. Менять его на системный ради балла нельзя: на этом сайте такая замена была бы видна сразу. Урезание по символам — другое дело, вид не меняется вовсе.

06Ядро Битрикса и мелочи, которые дают секунды

Дальше — самое неочевидное. Половину выигрыша дали не картинки, а то, что грузилось «по привычке».

Ядро отдавалось неминифицированным

Главный скрипт движка весил 543 КБ, и в отчёте висело «уменьшите размер кода JavaScript». Рядом на сервере лежала готовая минифицированная версия того же файла — 245 КБ. Залили её на место обычной. Проверка: объект BX создаётся, jQuery и Bootstrap на месте, слайдер и аккордеон работают, ошибок в консоли нет.

Слайдер грузился на всех страницах

Библиотека слайдеров — 40 КБ — подключалась везде, хотя слайдер есть на шести страницах из ста тридцати. Добавили условие: грузить, только если на странице есть элемент слайдера. На главной её больше нет.

Предзагрузка того, что нужно сразу

Два шрифта и главная картинка теперь объявлены в шапке как preload. Первая отрисовка: 1,9 → 1,3 секунды. Картинку предзагружаем только на тех страницах, где она есть, — иначе остальные страницы качали бы файл, которого у них нет.

Стили, вшитые в шапку

Тридцать килобайт CSS лежали прямо в разметке страницы, пятью блоками. Их сжали до шестнадцати (убрали комментарии и лишние пробелы), число правил не изменилось — 301 до и после.

Заглушка для ленивых картинок

Пока настоящие фото не догрузились, вместо них показывается картинка-заглушка. Она весила 10 КБ (600×400) и при этом была больше контейнера. Ужали до 3,7 КБ ровно в той же пропорции: первая попытка с другой пропорцией сдвинула один блок на 1–2 пикселя, и это поймал замер геометрии, а не глаза.

07Агентный просмотр и доступность

В отчёте Google появились две новые категории, и обе были в плохом состоянии: агентный просмотр — 1 из 3, доступность — 84.

Агентный просмотр: 1/3 → 3/3

Это проверка того, насколько сайт понятен ИИ-агентам и AI-поисковикам. Три условия: дерево доступности в порядке, вёрстка не прыгает и есть файл llms.txt со ссылками.

Файл llms.txt на сайте был, но проверка всё равно падала с формулировкой «файл не содержит ссылок»: адреса в нём были записаны обычным текстом, а нужны ссылки в разметке Markdown. Заодно не существовало файла agent.md, на который llms.txt ссылался.

Что былоСтало
llms.txt: 0 ссылок в разметке31 ссылка
llms-full.txt: 0 ссылок45 ссылок
agent.md: нет файла (404)есть, отдаётся как text/markdown

Доступность: 84 → 96

  • Четыре ссылки на соцсети были картинками без текста — добавили подписи для озвучки.
  • Кнопка мобильного меню — тоже без имени, теперь «Открыть меню».
  • Поля формы заявки шли без подписей вовсе: имя, телефон, почта, сообщение — подписали.
  • Серый текст #757575 давал контраст 4,41 при норме 4,5 — затемнили до #707070, стало 4,75.
грабля

Пункт «размер цели» так и остался незакрытым: телефонная ссылка в шапке высотой 19 px при норме 24. Я примерил увеличение области нажатия — шапка сдвигалась на 1–2 пикселя, и я откатил. Из-за этого доступность 96, а не 100: за балл не стал двигать вёрстку.

08Страница с шестью плеерами: 32 → 89

Когда главная уже показывала 95, одна внутренняя страница упорно держалась на 47. Причём дело было не в шаблоне: остальные страницы того же типа давали 83–93.

Страница «Занятия с нейролингвистом» — обычный текст, одна картинка на 25 КБ. Всё остальное приезжало из вставок в её содержимом:

  • шесть плееров Rutube — три ролика, каждый вставлен дважды: вариант для компьютера высотой 170 px и для телефона высотой 200 px;
  • чат-виджет — четыре своих файла и своя копия jQuery 3.2.1 с Google CDN, хотя jQuery у сайта уже была;
  • Google Tag Manager и рекламный бандл Яндекса с рекламного CDN.

Замер до правок: вес 1,4 МБ, 114 запросов, TBT 3,1–3,9 секунды, главная нить занята 7,4–8,7 секунды. LCP 8,9 секунды при картинке в 25 КБ — её просто не успевали показать.

Почему loading="lazy" не помог

Первым шагом я добавил отложенную загрузку всем шести плеерам (loading="lazy"). TBT упал с 3,1 с до 140 мс, но в отчёте всё равно остались три копии плеера по 679 КБ. Причина: на медленном соединении браузер подтягивает ленивые iframe заранее, за 3000–4000 пикселя до экрана, а видео стоят не так далеко. Отложенная загрузка спасает от мгновенной загрузки, но не от ранней.

Обложка вместо плеера

Надёжно режется только так: вместо живого плеера — картинка-кадр и кнопка, а настоящий плеер подставляется по нажатию. Кадры взяты из открытого API Rutube (/api/video/<id>/, поле thumbnail_url), ужаты до 720×405 и 22–40 КБ. Всего 17 уникальных роликов и 48 вставок в пяти общих файлах — то есть правка сделана не в одной странице, а везде, где эти блоки выводятся (37 страниц с видео).

// обработчик один, в подвале шаблона: обложка -> живой плеер
var box = e.target.closest('.rt-facade');
if (!box) return;
var ifr = document.createElement('iframe');
ifr.src = box.getAttribute('data-src') + '?autoStart=true';
ifr.width = '99%';
ifr.height = box.getAttribute('data-h');
box.parentNode.replaceChild(ifr, box);

Чат-виджет, который давал 2,3 секунды блокировки, переведён на загрузку после первого действия посетителя (прокрутка, клик, клавиша) или через пять секунд. Файл виджета не менялся — изменился только момент, когда его скрипты подключаются.

Одна и та же страница до и после:
вес, было1 394 КБ
вес, стало442 КБ
TBT, было3 100 мс
TBT, стало80 мс
ПоказательБылоСтало
Балл производительности32–4788–89
LCP8,9 с3,2 с
Первая отрисовка3,0 с1,4 с
TBT3 100 мс80–170 мс
Вес страницы1 394 КБ442 КБ
Запросов11438
проверено

До нажатия на обложку — ни одного iframe и ни одного запроса к плееру. После нажатия появляется iframe нужного размера с адресом ролика и параметром автозапуска, загрузка плеера начинается. То есть видео работает как раньше, просто не грузится заранее.

грабля

Кнопка чата на этих страницах не работала и до правок: в консоли падает TypeError ... setting 'onclick' в config.js, а элемента .chatbot__btn, на который он ссылается, в разметке нет. Виджет честно загружался — и ничего не делал. Проверил на исходной версии специально, чтобы не свалить это на свои правки: ошибка та же. Вывод на будущее: проверять не «скрипт загрузился», а «виджет работает».

Что осталось на этой странице: Google Tag Manager (122 КБ, в отчёте показан трижды), рекламный бандл Яндекса (227 КБ) и Метрика. Это чужие счётчики, их откладывают отдельно и с согласия владельца — молча не трогал.

09Что осталось и что не вышло

Не вышло:

  • Убрать служебные стили движка. В шапке осталось три файла Битрикса: стили всплывающих окон (6,8 КБ), токены интерфейса (4,7 КБ) и шрифт Open Sans (0,6 КБ). В отчёте они дают 960 мс блокировки. Штатный способ — отфильтровать список подключаемых файлов — привёл к тому, что движок пересобрал все стили в один файл на 1,5 КБ, и страница осталась без оформления. Откатил за пару минут; сайт и сейчас в порядке, но приём повторять без отдельного согласия не буду.
  • Убрать полифилы из ядра. 19 КБ кода для старых браузеров и 47 КБ неиспользуемого кода лежат внутри ядра Битрикса. Это пересборка движка — отдельная задача с отдельными рисками.
  • Ускорить кэш css и js из файла на диске. Их отдаёт nginx, из .htaccess это не меняется — владелец включил годовой кэш в панели хостинга.

Осталось на решение владельца:

  • LCP 3,3 секунды. Картинка скачивается за 100 мс, но показ ждёт, пока браузер разберёт тридцать килобайт стилей из шапки. Вынос их в общий файл — последний крупный резерв, и он трогает порядок правил, то есть может повлиять на вид.
  • Фон одного из блоков весит 124 КБ. Его можно ужать до семидесяти, но на большом экране он станет мягче. Это уже вопрос вкуса, а не техники.

10Чек-лист, если делать у себя

  • Начать с раскрытых пунктов отчёта: там перечислены файлы и их вклад в миллисекундах. Без этого списка правки идут наугад.
  • Мерить по три-пять прогонов и сравнивать медиану — одиночный замер на Битриксе ничего не значит.
  • Проверить каждый тяжёлый файл внутрь: SVG с вложенной картинкой, шрифт со всеми алфавитами, «минифицированный» файл, который на самом деле не минифицирован.
  • Кэш проверять отдельным запросом по каждому типу файла, а не «по расширениям на глаз»: часть статики может отдавать nginx мимо ваших правил.
  • Урезая CSS, не вырезать правила компонентов, которыми управляет скрипт. Признак поломки: элементов на странице столько же, ошибок в консоли ноль, а меню не открывается.
  • После каждой правки сравнивать геометрию всех элементов страницы с исходной, а не полагаться на снимок: на живом сайте с анимацией и ленивой загрузкой два снимка одного и того же кода расходятся до процента точек.
  • Шрифт урезать по символам, а не менять на системный: первое не видно, второе видно всем.
  • Проверять кликом: меню, вложенные пункты, выпадающие списки, аккордеоны, модальные окна — на телефоне и на компьютере.
  • Чужие плееры выносить в обложку с кнопкой: loading="lazy" на медленном соединении не спасает, браузер тянет iframe за несколько тысяч пикселей до экрана.
  • Виджеты (чаты, квизы, отзывы) грузить после первого действия посетителя. И проверять, что виджет после этого работает: «скрипт загрузился» не значит «кнопка нажимается».

Материал подготовлен по итогам работ 23 октября 2026 года на боевом сайте сети логопедических центров (Битрикс, общий хостинг, доступ только по FTP).

Числа — из фактических замеров: Lighthouse 13 в телефонном профиле (медленная сеть, четырёхкратное замедление процессора) и настольном, по 3–5 прогонов на состояние; вес файлов — HTTP-запросами к живому сайту; проверка вида — сравнением геометрии всех элементов страницы до и после правки. Итоговые баллы PageSpeed: производительность 95, доступность 96, рекомендации 100, поисковая оптимизация 100, агентный просмотр 3 из 3. Отдельно проверялась внутренняя страница с видео и чатом: 32–47 → 88–89.




Категории:

Категории

← Назад к списку