Хіт 100 у всіх чотирьох категоріях Lighthouse — Performance, Accessibility, Best Practices, SEO — звучить неможливо. Або гірше — звучить як річ, що потребує хаків: безглуздих трюків, щоб гейміти бал, що роблять реальний UX гіршим.
Це не одне з цього. Lighthouse 100 по всьому — це проблема стека і дисципліни. Оберіть правильний стек, тримайте дисципліну — і бали приходять без трюків. Чотири 100 навіть не особливо вражають, коли їх побачив; це side effect від послідовного виконання базових речей.
Цей пост — плейбук. Стек, який ми використовуємо, дисципліна, що тримає бали, і кейс, де ми хітнули чотири 100 на реальному проєкті.
Що насправді означає «100» на категорію
Кожна категорія Lighthouse вимірює різне. Варто бути точним:
Performance (100):
- Largest Contentful Paint (LCP) під 1.2s на синтетичному mid-tier мобільному профілі.
- Total Blocking Time (TBT) під 200ms.
- Cumulative Layout Shift (CLS) під 0.1.
- Speed Index під 3.4s.
- First Contentful Paint (FCP) під 1.8s.
На практиці хітайте усі п'ять — і бал 100. Пропустіть один — падає до 95-99.
Accessibility (100):
- Усі автоматизовані перевірки пройдено: alt-текст, ARIA-коректність, контраст, лейбли форм, ієрархія заголовків, мовний атрибут, текст посилань.
- Близько 50 конкретних перевірок. Аудит бінарний на перевірку; 100 означає, що всі пройдено.
Lighthouse ловить лише автоматизовану підмножину (~30% реальних accessibility-проблем). Хіт 100 тут — необхідний, але недостатній для справжньої доступності.
Best Practices (100):
- HTTPS скрізь, без mixed content.
- Жодних застарілих API у використанні.
- Жодних помилок консолі.
- Жодних security-вразливостей у виявлених залежностях.
- Правильні заголовки Content Security Policy (недавнє додавання).
- Зображення використовують сучасні формати і розумні aspect ratio.
SEO (100):
- Title і meta description присутні і розумної довжини.
- Сторінка crawlable (robots.txt дозволяє, без
<meta robots noindex>). - Посилання мають описовий текст.
- Сторінка має viewport meta-тег.
- Документ має
<title>і<html lang="...">.
Найпростіша з чотирьох. Більшість шаблонів отримують це безкоштовно.
Стек, що робить 100 досяжним
Конкретні технологічні і конфігураційні вибори, що складаються, щоб зробити чотири 100 реалістичними:
Фреймворк: Next.js App Router (server-first)
Серверні компоненти рендерять HTML на сервері. Браузер отримує готовий HTML, не JavaScript-блоб, що має гідрувати. Це найбільший одиничний фактор для Performance-балів.
Важкий SPA-фреймворк (React Router у client-режимі, дефолтний Vite + React setup) відправляє сотні KB JavaScript до того, як щось рендериться. Серверні компоненти відправляють JS лише для інтерактивних частин, що на маркетинговому сайті — мала частка сторінки.
Хостинг: edge або CDN-fronted
Статичний HTML, що сервується з edge, має TTFB під 100ms будь-де у світі. Динамічний HTML з single-region origin має TTFB 200-400ms поза тим регіоном. Performance-бал чутливий до TTFB; сервінг з edge — безкоштовні 5-10 балів у середньому.
Ми за замовчуванням беремо Vercel за простоту. Cloudflare Workers + Pages — інший відмінний вибір. Self-hosting з Cloudflare попереду origin-сервера теж працює.
Зображення: дисципліна формату і розміру
Кожне зображення:
- Сервується як WebP або AVIF, не JPEG/PNG (сучасні формати на 25-50% менші за ту саму якість).
- Має атрибути
widthіheight(запобігає CLS). - Має
srcsetз кількома розмірами (браузери завантажують правильний розмір, не завжди найбільший). - Має
priorityна hero (preload-ить замість того, щоб чекати layout). - Має
loading="lazy"на решті (відкладає off-screen зображення).
Це дисципліна, яку набридливо забезпечувати вручну. Використайте компонент <Image> Next.js (або еквівалент), і це оброблено. Обійдіть компонент — і ні.
Шрифти: subset і preload
- Self-host шрифти (не вантажте з Google Fonts на рантаймі; нехай ваш білд їх притягує).
- Subset до символів, які ви насправді використовуєте (англійська + ваша конкретна локаль).
- Використайте
font-display: swap(краще LCP) абоoptional(найкраще LCP, найгірша fidelity шрифту). - Preload критичний шрифт у head:
<link rel="preload" as="font" href="..." crossorigin>.
Ці чотири разом роблять різницю між шрифтами, що блокують рендеринг, і тими, що ні.
JavaScript: мінімальний і code-split
- Використайте серверні компоненти за замовчуванням; client-компоненти лише там, де інтерактивність потрібна.
- Аудитуйте бандл. Усе більше за 100KB gzip на першому завантаженні має мати виправдання.
- Динамічно імпортуйте некритичні компоненти (модалки, dropdown-и, що ще не відкриті).
- Жодних polyfill-ів для браузерів, які не підтримуєте.
Маркетинговий сайт має відправляти 30-100KB JavaScript на першому завантаженні. Якщо ваш відправляє більше — у вас є можливість.
CSS: Tailwind + tree-shake
Tailwind відправляє лише класи, які ви насправді використовуєте. Фінальний CSS-файл для типового маркетингового сайту — 5-15KB gzip, навіть з сотнями сторінок. Tree-shaking працює автоматично.
Альтернатива (component-бібліотеки, що відправляють 200KB CSS) робить Lighthouse 100 важким або неможливим без агресивного purging.
Third-party скрипти: безжальна фільтрація
Аналітика, чат-віджети, A/B-тести, підтримка. Кожен — «лише маленький скрипт». Сукупно вони коштують 50-100 балів Performance.
Дисципліна:
- Privacy-respecting аналітика (Plausible, Umami) замість GA4, якщо можна. Менші скрипти, без consent-banner.
- Вантажте чат-віджети лазі — не на першому паінті, а на користувацькому інтенті.
- A/B-тести або на edge (без client-side скрипта), або пропустіть повністю.
- Marketing automation pixel-и: defer або приберіть, якщо можна.
Для більшості маркетингових сайтів, які ми відвантажуємо: один analytics-скрипт (Plausible, ~1KB), без чат-віджета, без marketing pixel-ів. Сайт вантажиться швидко, бо нічого не пригальмовує.
Дисципліна, що тримає бали
Lighthouse 100 на запуску — досяжне. Тримати рік — складніша проблема. Три звички:
1. Lighthouse на кожному PR
Запускайте Lighthouse CI проти staging на кожному pull request. Фейліть білд, якщо будь-яка категорія падає нижче threshold (ми використовуємо 95 як підлогу; нижче — PR потребує виправдання).
Це ловить повільний дрифт. Нове зображення без priority. Новий third-party скрипт. Регресія у CSS, що зламала font-display. Без CI-перевірок ці накопичуються.
2. Забезпечення бюджету бандла
bundlesize або size-limit у test-suite. JavaScript першого завантаження має бюджет (наприклад, 100KB gzip). Будь-який PR, що перевищує бюджет, фейлиться.
Коли бюджет хітнуто, команда змушена або виправдати збільшення, або обрізати щось інше. Без бюджету розмір бандла лише росте.
3. Квартальне ревью third-party скриптів
Щокварталу хтось ревьюїть список third-party скриптів, що вантажаться на сайті. Спитайте кожного: «Чому це досі тут? Коли ми востаннє це використовували?».
Маркетингові команди додають скрипти. Маркетингові команди рідко прибирають. Квартальне ревью — єдиний механізм, що запобігає поступовому розпаду кожного бала.
Реальний проєкт
Ми хітнули Lighthouse 100 у всіх чотирьох категоріях на B2B SaaS-маркетинговому сайті, який нещодавно відвантажили. Цифри, виміряні у лабі:
- Performance: 100 (LCP 0.9s, CLS 0.02, FCP 0.8s, Speed Index 1.4s)
- Accessibility: 100 (усі автоматизовані перевірки)
- Best Practices: 100
- SEO: 100
Стек: Next.js App Router, Vercel, Tailwind, Plausible аналітика. Без чат-віджета. Без marketing automation. Кастомний Sanity-backed CMS з вбудованою Studio.
Зусилля білду були не значно більшими за «хороший, але не 100» сайт. Різниця була у дисципліні на маргіналі: кожне зображення йшло через <Image>, кожен інтерактивний елемент був client-component, лише коли треба, кожен third-party скрипт отримував виправдання.
Через місяць після запуску з content-правками і кількома новими фічами бали були Performance 98, Accessibility 100, Best Practices 100, SEO 100. 98 викликало одним PR, що додав background-зображення без srcset. Lighthouse CI помітив на наступному PR; ми виправили; назад до 100.
Шість місяців пізніше бали досі 99-100 по всьому. CI робить свою роботу.
Де чотири 100 — overkill
Чесні випадки, де гонитва за цим — втрачені зусилля:
Внутрішній інструмент. Продуктивність усе ще важить (юзери — команда). Доступність важить юридично і морально. Але не треба 100; 80-90 вистачить для внутрішнього CRUD-застосунку.
Застосунок, де маркетингова сторінка — одна з п'ятдесяти. Маркетингова сторінка має хітнути 100. Сторінки застосунку (за логіном) мають інші обмеження; цілитись у 100 там — інший проєкт.
Контент-сайт з важкою user-uploaded media. Якщо не можете контролювати якість зображень (юзери завантажують, що завантажують), не зможете хітнути Performance 100 по всьому. Сфокусуйтесь на хіт-і на сторінках, які контролюєте.
Сайт, що ось-ось буде перебудований. Не витрачайте три тижні на оптимізацію сайту, який заміните за шість. Час подорожує погано.
Підсумок
- Lighthouse 100 у всіх чотирьох категоріях — це проблема стека і дисципліни.
- Серверні компоненти, edge-хостинг, image-дисципліна, мінімум JS, безжальна фільтрація third-party.
- CI-забезпечення тримає бали після запуску.
- Квартальне ревью запобігає поступовому розпаду.
- Це overkill для деяких випадків, дефолт для інших.
Чотири 100 — досяжні на будь-якому маркетинговому сайті, побудованому на правильному стеку. Це side effect від послідовного виконання базових речей, не хак.
Якщо хочете маркетинговий сайт, побудований під чотири 100 (і підтримуваний на них), подивіться, як ми працюємо з редизайном і підтримкою.