Оптимізація LCP (Largest Contentful Paint)
LCP — час появи найбільшого елемента у viewport. Мета: ≤ 2,5 секунди. Звичайно це hero-зображення, H1 або великий текстовий блок.
Діагностика: що є LCP-елементом
DevTools → Performance → запис завантаження сторінки → знайти маркер LCP. Або через консоль:
new PerformanceObserver((list) => {
const entries = list.getEntries();
const last = entries[entries.length - 1];
console.log('LCP element:', last.element);
console.log('LCP time:', last.startTime);
}).observe({ type: 'largest-contentful-paint', buffered: true });
Оптимізація зображення (основний LCP-елемент)
<!-- 1. Preload — найважливіший крок -->
<link rel="preload" as="image"
href="/images/hero.webp"
imagesrcset="/images/hero-640.webp 640w,
/images/hero-1280.webp 1280w,
/images/hero-1920.webp 1920w"
imagesizes="100vw"
fetchpriority="high">
<!-- 2. Тег зображення з fetchpriority -->
<img src="/images/hero.webp"
srcset="/images/hero-640.webp 640w,
/images/hero-1280.webp 1280w,
/images/hero-1920.webp 1920w"
sizes="100vw"
width="1920" height="1080"
alt="Опис зображення"
fetchpriority="high"
loading="eager"
decoding="async">
loading="lazy" на LCP-зображенні — розповсюджена помилка. Ленива загрузка затримує завантаження, збільшуючи LCP.
Прискорення TTFB (сервер)
LCP = TTFB + час завантаження ресурсу. Повільний TTFB робить хороший LCP неможливим.
// Laravel: Full Page Cache для публічних сторінок
// Пакет spatie/laravel-responsecache або nginx fastcgi_cache
// Мінімальний FPC middleware
class CacheResponse
{
public function handle(Request $request, Closure $next): Response
{
if (!$request->isMethod('GET') || auth()->check()) {
return $next($request);
}
$key = 'fpc:' . md5($request->fullUrl());
$cached = Cache::get($key);
if ($cached) {
return response($cached['body'], 200, $cached['headers'])
->header('X-Cache', 'HIT');
}
$response = $next($request);
if ($response->isOk()) {
Cache::put($key, [
'body' => $response->getContent(),
'headers' => ['Content-Type' => 'text/html; charset=UTF-8'],
], now()->addMinutes(5));
}
return $response;
}
}
# nginx fastcgi_cache
fastcgi_cache_path /var/cache/nginx levels=1:2 keys_zone=FCGI:10m inactive=60m;
location ~ \.php$ {
fastcgi_cache FCGI;
fastcgi_cache_valid 200 5m;
fastcgi_cache_bypass $cookie_session $http_authorization;
fastcgi_no_cache $cookie_session $http_authorization;
add_header X-Cache $upstream_cache_status;
}
CSS — усунення render-blocking
<!-- Critical CSS inline, решта async -->
<style>/* критичний CSS для above-the-fold */</style>
<link rel="preload" href="/css/app.css" as="style"
onload="this.onload=null;this.rel='stylesheet'">
<noscript><link rel="stylesheet" href="/css/app.css"></noscript>
Генерація critical CSS: Vite + critters плагін (інлайнує critical CSS автоматично при збірці).
// vite.config.ts
import { critters } from 'critters';
export default defineConfig({
plugins: [
critters({ preload: 'swap', pruneSource: false })
]
});
Шрифти
<!-- Preconnect до Google Fonts -->
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<!-- Preload найбільш використовуваного граничного шрифту -->
<link rel="preload" as="font" type="font/woff2"
href="/fonts/inter-regular.woff2" crossorigin>
Background image як LCP
Якщо LCP-елемент — CSS background-image, браузер не може його preload автоматично. Краще замінити на <img> або використовувати fetchpriority через Speculation Rules (Chrome 121+):
// Для background-image — явний preload через JS
const link = document.createElement('link');
link.rel = 'preload';
link.as = 'image';
link.href = '/images/hero-bg.webp';
document.head.appendChild(link);
Цільові показники за типами сторінок
| Тип сторінки | Реалістична мета LCP |
|---|---|
| Лендинг | 1,5–2,0 с |
| Головна сторінка інтернет-магазину | 2,0–2,5 с |
| Карточка товару | 2,0–2,5 с |
| Стаття блогу | 1,5–2,0 с |
Час оптимізації: 3–5 днів з урахуванням налаштування збірки, кешування та аналізу.







