Оптимизация 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-изображении — распространённая ошибка. Lazy loading откладывает загрузку, увеличивая 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 плагин (inlines 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 дней с учётом настройки сборки, кеша и анализа.







