Astro calendar_today 23 апр. 2026 г. schedule 3 мин

Core Web Vitals в Astro: Как получить 100/100 в PageSpeed

Как оптимизировать Core Web Vitals (LCP, INP, CLS) в Astro.js: практические техники, чеклист и инструменты для достижения PageSpeed 100 на мобильных и десктопе.

person
Журналист
Автор
Core Web Vitals в Astro — LCP, INP, CLS: оптимизация и PageSpeed 100

Core Web Vitals — три метрики Google, официально влияющие на ранжирование с 2021 года. Astro из коробки близок к идеалу, но даже здесь есть точки роста. Этот гайд — исчерпывающий разбор каждой метрики с конкретными приёмами.

Что такое Core Web Vitals

МетрикаРасшифровкаХорошоПлохо
LCPLargest Contentful Paint≤ 2.5 с> 4 с
INPInteraction to Next Paint≤ 200 мс> 500 мс
CLSCumulative Layout Shift≤ 0.1> 0.25

Astro SSG из коробки обычно показывает:

  • LCP: 0.5–1.2 с
  • INP: < 50 мс ✅ (нет JS → нет долгих задач)
  • CLS: 0 ✅ (при правильном коде)

1. LCP — Largest Contentful Paint

LCP — время до отрисовки самого большого видимого элемента: обложка, hero-изображение или крупный заголовок.

Главные враги LCP

Изображение обложки без preload и eager:

code
---
// ❌ Плохо
import { Image } from 'astro:assets';
import cover from '../assets/cover.jpg';
---

<img src={cover.src} alt="..." loading="lazy" />

// ✅ Хорошо: eager + fetchpriority + WebP
<Image
  src={cover}
  alt="Описание для SEO"
  width={1200}
  height={630}
  format="webp"
  quality={85}
  loading="eager"
  fetchpriority="high"
/>

Нет preload для hero-изображения:

code
---
// src/layouts/ArticleLayout.astro
const { coverUrl } = Astro.props;
---

<head>
  {coverUrl && <link rel="preload" as="image" href={coverUrl} fetchpriority="high" />}
  <link
    rel="preload"
    href="/fonts/inter-variable.woff2"
    as="font"
    type="font/woff2"
    crossorigin
  />
</head>

Шрифты блокируют рендеринг:

code
/* ✅ font-display: swap + preload */
@font-face {
  font-family: 'Inter';
  src: url('/fonts/inter-variable.woff2') format('woff2');
  font-weight: 100 900;
  font-display: swap;
}

Проверить LCP-элемент в DevTools

code
new PerformanceObserver((list) => {
  const last = list.getEntries().at(-1);
  console.log('LCP element:', last.element);
  console.log('LCP time:', last.startTime.toFixed(0) + ' мс');
}).observe({ entryTypes: ['largest-contentful-paint'] });

2. INP — Interaction to Next Paint

INP (заменил FID в 2024) — задержка ответа на любое взаимодействие: клик, тап, ввод.

Почему Astro идеален для INP

У статических страниц практически нет JS в Main Thread. Проблемы начинаются с тяжёлыми островами:

code
---
// ❌ Плохо: загружается сразу, блокирует Main Thread
import HeavyChart from './HeavyChart.tsx';
---

<HeavyChart data={bigData} client:load />

// ✅ Хорошо: только когда в viewport
<HeavyChart data={bigData} client:visible />

// ✅ Ещё лучше: при простое браузера
<HeavyChart data={bigData} client:idle />

Тяжёлые обработчики — главная ловушка

code
// ❌ Плохо: синхронная обработка блокирует UI
function handleClick() {
  const result = heavyComputation(bigData);
  setResult(result);
}

// ✅ Хорошо: уступить управление, потом выполнить
function handleClick() {
  setLoading(true);
  setTimeout(() => {
    const result = heavyComputation(bigData);
    setResult(result);
    setLoading(false);
  }, 0);
}

3. CLS — Cumulative Layout Shift

CLS — суммарный сдвиг элементов во время загрузки страницы.

Изображения без размеров — главная причина CLS

code
---
// ❌ Плохо: браузер не знает высоту до загрузки
---

<img src="/photo.jpg" alt="Фото" />

// ✅ Хорошо: explicit width + height
<img src="/photo.jpg" alt="Фото" width="800" height="600" />

// ✅ Ещё лучше: через astro:assets (размеры автоматически) import {Image} from 'astro:assets';
import photo from '../assets/photo.jpg'; ---
<Image src={photo} alt="Фото" />

Шрифты вызывают FOUT (Flash of Unstyled Text)

code
/* size-adjust минимизирует сдвиг при замене шрифта */
@font-face {
  font-family: 'FallbackInter';
  src: local('Arial');
  size-adjust: 107%;
  ascent-override: 90%;
  descent-override: 22%;
}

body {
  font-family: 'Inter', 'FallbackInter', system-ui, sans-serif;
}

Уведомления — частый виновник сдвига

code
// ❌ Плохо: вставляется в flow и сдвигает контент
<div style={{ position: 'relative' }}>Уведомление</div>

// ✅ Хорошо: fixed выходит из flow документа
<div style={{ position: 'fixed', bottom: '16px', right: '16px' }}>
  Уведомление
</div>

Измерение Core Web Vitals

web-vitals библиотека

code
npm install web-vitals
code
---
// src/layouts/BaseLayout.astro
---

<script>
  import { onLCP, onINP, onCLS } from 'web-vitals';

  function report({ name, value, rating }) {
    console.log(`${name}: ${Math.round(value)} мс — ${rating}`);
    // Отправить в аналитику:
    gtag?.('event', name, { value: Math.round(value), metric_rating: rating });
  }

  onLCP(report);
  onINP(report);
  onCLS(report);
</script>

Инструменты

ИнструментТип данныхСсылка
PageSpeed InsightsЛаб + реальные пользователиpagespeed.web.dev
LighthouseЛабораторныеDevTools → Lighthouse
Chrome Web VitalsРеальный визитРасширение Chrome
Search ConsoleРеальные пользователи (агрегат)search.google.com/console
CrUX DashboardИстория трендаLooker Studio

Чеклист Core Web Vitals для Astro

LCP:

  • Hero/обложка с loading="eager" и fetchpriority="high"
  • <link rel="preload"> для hero-изображения в <head>
  • Шрифты с font-display: swap + <link rel="preload">
  • Формат WebP/AVIF (экономия 30-50% веса)
  • TTFB < 200 мс — хостинг на CDN (Cloudflare Pages)

INP:

  • Минимум client:load — заменить на client:visible / client:idle
  • Нет синхронных тяжёлых операций в onClick/onChange
  • Total Blocking Time < 200 мс в Lighthouse

CLS:

  • Все <img> с явными width и height
  • Использовать <Image /> из astro:assets (авторазмеры)
  • Зарезервированы места для рекламы / динамического контента
  • font-display: swap для всех кастомных шрифтов
  • Уведомления через position: fixed

Типичный результат после оптимизации

МетрикаДоПосле
LCP3.2 с0.8 с
INP350 мс< 50 мс
CLS0.180.02
PageSpeed Mobile6298

Итог

Astro даёт отличный старт для Core Web Vitals, но нужно контролировать изображения без размеров, лишние client:load острова и тяжёлые обработчики событий. Настройте мониторинг через web-vitals и отслеживайте регрессии при каждом деплое. Подробнее о SEO-стратегии — в статье SEO для Astro.

Портрет автора Дмитрий Соколов

Senior Frontend Engineer / Tech Writer

Senior Frontend Engineer с 9-летним опытом. Специализируется на Astro.js и JAMstack.

Комментарии

Загрузка комментариев...

Оставить комментарий

Комментарии проходят модерацию перед публикацией. Правила

Рекомендуем к прочтению