Перейти к содержанию
Acecore

Практические техники достижения 99 баллов PageSpeed Mobile на сайте Astro

by Gui
Содержание
Практические техники достижения 99 баллов PageSpeed Mobile на сайте Astro

Введение

Официальный сайт Acecore построен на Astro 6 + UnoCSS + Cloudflare Pages. В этой статье представлены техники оптимизации, использованные для достижения Mobile 99 / Desktop 100 в PageSpeed Insights.

Достигнутые итоговые оценки:

МетрикаMobileDesktop
Performance99100
Accessibility100100
Best Practices100100
SEO100100

Почему Astro?

Корпоративные сайты требуют «скорости» и «SEO». Astro специализируется на статической генерации сайтов (SSG) и обеспечивает нулевой JavaScript по умолчанию. В отличие от фреймворков вроде React или Vue, код фреймворка не отправляется клиенту, что обеспечивает чрезвычайно быстрый начальный рендеринг.

UnoCSS был выбран в качестве CSS-фреймворка. Как и Tailwind CSS, он использует подход utility-first, но извлекает только используемые классы при сборке для минимизации размера CSS. Начиная с v66 рекомендуется presetWind3(), поэтому обязательно мигрируйте.


Стратегия доставки CSS: встроенный vs внешний

Стратегия доставки CSS оказала наибольшее влияние на оценки PageSpeed.

Когда CSS небольшой (~20 КиБ)

Установка build.inlineStylesheets: 'always' в Astro встраивает весь CSS прямо в HTML. Это исключает HTTP-запросы к внешним CSS-файлам, улучшая FCP (First Contentful Paint).

Этот подход оптимален, когда CSS составляет около 20 КиБ и менее.

Когда CSS большой (20 КиБ+)

Однако использование японских веб-шрифтов (@fontsource-variable/noto-sans-jp) меняет ситуацию. Этот пакет содержит 124 объявления @font-face (~96,7 КиБ), доводя общий CSS до примерно 190 КиБ.

Встраивание 190 КиБ CSS в каждую HTML-страницу раздувает главную до 225 КиБ. На медленном 4G передача одного только HTML занимает около 1 секунды.

Решение: вынесение во внешний файл + неизменяемый кэш

Измените настройку Astro на build.inlineStylesheets: 'auto'. Astro автоматически примет решение на основе размера CSS, отдавая большой CSS как внешние файлы.

// astro.config.mjs
export default defineConfig({
  build: {
    inlineStylesheets: 'auto',
  },
})

Внешние CSS-файлы выводятся в директорию /_astro/, поэтому примените неизменяемый кэш через настройки заголовков Cloudflare Pages.

/_astro/*
  Cache-Control: public, max-age=31536000, immutable

Это изменение уменьшило размер HTML на 84–91% (например, index.html с 225 КиБ → 35 КиБ) и подняло оценку PageSpeed с 96 → 99.


Оптимизация шрифтов: правильная настройка самостоятельного размещения

Избегайте Google Fonts CDN

Google Fonts CDN удобен, но губителен в мобильных тестах PageSpeed Insights. При тестировании использование Google Fonts CDN снизило FCP до 6,1 секунды, а оценку до 62.

На медленном 4G подключение к внешнему домену запускает цепочку DNS-запрос → TCP-соединение → TLS-рукопожатие → загрузка CSS → загрузка шрифта, значительно задерживая рендеринг.

Внедрение самостоятельного размещения

Просто установите @fontsource-variable/noto-sans-jp и импортируйте его в файле макета.

npm install @fontsource-variable/noto-sans-jp
// BaseLayout.astro
import '@fontsource-variable/noto-sans-jp'

Осторожно: несоответствие имени шрифта

Вот неочевидный подводный камень. Имя шрифта, зарегистрированное @fontsource-variable/noto-sans-jp в @font-face, — Noto Sans JP Variable. Однако многие пишут в CSS Noto Sans JP.

Это несоответствие означает, что шрифт не применяется, и используется запасной шрифт браузера. Несмотря на загрузку 96,7 КиБ шрифтовых данных, ничего из них не используется.

Укажите правильное семейство шрифтов в настройках UnoCSS:

// uno.config.ts
theme: {
  fontFamily: {
    sans: "'Noto Sans JP Variable', 'Hiragino Kaku Gothic ProN', 'メイリオ', sans-serif",
  },
}

Если возникнут ошибки типов TypeScript, добавьте объявление модуля в src/env.d.ts:

declare module '@fontsource-variable/noto-sans-jp';

Оптимизация изображений: wsrv.nl + srcset + sizes

Прокси wsrv.nl

Внешние изображения обслуживаются через wsrv.nl. Простое добавление параметров URL обеспечивает:

  • Конвертацию формата: output=auto автоматически выбирает AVIF/WebP в зависимости от поддержки браузера
  • Настройку качества: q=50 сохраняет достаточное качество при уменьшении размера файла на ~10%
  • Изменение размера: параметр w= изменяет размер до указанной ширины

Настройка srcset и sizes

Установите srcset и sizes на все изображения для доставки оптимальных размеров в зависимости от ширины экрана.

<img
  src="https://wsrv.nl/?url=...&w=800&output=auto&q=50"
  srcset="
    https://wsrv.nl/?url=...&w=480&output=auto&q=50 480w,
    https://wsrv.nl/?url=...&w=640&output=auto&q=50 640w,
    https://wsrv.nl/?url=...&w=960&output=auto&q=50 960w,
    https://wsrv.nl/?url=...&w=1280&output=auto&q=50 1280w,
    https://wsrv.nl/?url=...&w=1600&output=auto&q=50 1600w
  "
  sizes="(max-width: 768px) calc(100vw - 2rem), 800px"
  loading="lazy"
  decoding="async"
/>

Точность sizes

Если атрибут sizes оставить как 100vw (полная ширина экрана), браузер будет выбирать изображения большего размера, чем нужно. Укажите в соответствии с реальным макетом, например calc(100vw - 2rem) или (max-width: 768px) 100vw, 50vw.

Улучшение LCP: preload

Установите <link rel="preload"> для изображений, влияющих на LCP (Largest Contentful Paint). Добавьте проп preloadImage в компонент макета Astro для указания изображений, которые должны загружаться с наивысшим приоритетом, таких как изображения на главном экране.

<link rel="preload" as="image" href="..." />

Предотвращение CLS (сдвиг макета)

Укажите атрибуты width и height для всех изображений. Это позволяет браузеру заранее зарезервировать пространство для отображения, предотвращая сдвиги макета (CLS) при завершении загрузки.

Часто упускаемые изображения: аватары (32×32, 48×48, 64×64px) и миниатюры YouTube (480×360px).


Ленивая загрузка рекламы и аналитики

AdSense

Скрипт Google AdSense весит примерно 100 КиБ и значительно влияет на начальный рендеринг. Динамически внедряйте скрипт при первой прокрутке пользователя.

window.addEventListener('scroll', () => {
  const script = document.createElement('script')
  script.src = 'https://pagead2.googlesyndication.com/...'
  script.async = true
  document.head.appendChild(script)
}, { once: true })

{ once: true } гарантирует, что обработчик события сработает только один раз. Это сводит передачу JavaScript при первом показе практически к нулю.

GA4

Google Analytics 4 аналогично внедряется лениво с использованием requestIdleCallback. Скрипт внедряется, когда браузер простаивает, избегая помех при взаимодействии пользователя.


Стратегия кэширования

Установите оптимальные политики кэширования для каждого типа ресурсов в файле _headers Cloudflare Pages.

# Результат сборки (хэшированные имена файлов)
/_astro/*
  Cache-Control: public, max-age=31536000, immutable

# Поисковый индекс
/pagefind/*
  Cache-Control: public, max-age=604800, stale-while-revalidate=86400

# HTML
/*
  Cache-Control: public, max-age=0, must-revalidate
  • /_astro/* включает хэши содержимого в именах файлов, что делает годовой неизменяемый кэш безопасным
  • /pagefind/* получает недельный кэш + однодневный stale-while-revalidate
  • HTML всегда запрашивает последнюю версию

Чек-лист оптимизации производительности

  1. Правильна ли стратегия доставки CSS?: встраивание ниже 20 КиБ, вынесение выше
  2. Размещены ли шрифты на своём сервере?: внешний CDN губителен на медленном 4G
  3. Правильно ли имя шрифта?: проверьте зарегистрированное имя @fontsource-variable (*Variable)
  4. Есть ли у всех изображений srcset + sizes?: особенно подготовьте меньшие размеры для мобильных
  5. Есть ли preload у элемента LCP?: изображения на главном экране и изображения первого экрана
  6. Указаны ли width/height у изображений?: предотвращение CLS
  7. Загружаются ли AdSense/GA4 лениво?: нулевая передача JS при первом показе
  8. Настроены ли заголовки кэширования?: неизменяемый кэш для ускорения последующих визитов

Заключение

Принцип оптимизации производительности можно выразить одной фразой: «Не отправляйте лишнее». Встраивание CSS выглядит быстрым на первый взгляд, но при 190 КиБ даёт обратный эффект. Самостоятельное размещение шрифтов необходимо, но несоответствие имени шрифта — скрытая ловушка.

Опираясь на архитектуру Astro с нулевым JS и минимизируя передачу CSS, шрифтов, изображений и рекламных скриптов, мобильная оценка 99 вполне достижима.


Серия статей

Эта статья является частью серии «Руководство по улучшению качества сайта на Astro». Отдельные статьи также посвящены SEO, доступности и улучшению UX.

Рабочий процесс оптимизации

Стратегия доставки CSS

Понимание компромиссов между встроенным и внешним CSS.

Оптимизация шрифтов

Размещение шрифтов на своём сервере для устранения задержки внешнего CDN.

Оптимизация изображений

Доставка оптимальных размеров через wsrv.nl + srcset + sizes.

Ленивая загрузка

Внедрение AdSense и GA4 при первом взаимодействии пользователя.

До и после оптимизации

До оптимизации
  • Google Fonts CDN (блокирует рендеринг)
  • 190 КиБ CSS встроено в HTML
  • Изображения отдаются фиксированного размера
  • Скрипт AdSense загружается немедленно
  • Мобильная оценка в районе 70

После оптимизации
  • Самостоятельное размещение через @fontsource (с правильной ссылкой на имя шрифта)
  • CSS вынесен во внешний файл с неизменяемым кэшем
  • srcset + sizes для доставки изображений, оптимизированных под ширину экрана
  • AdSense и GA4 загружаются лениво при первой прокрутке
  • Mobile 99 / Desktop 100
Часто задаваемые вопросы
Что быстрее — встроенный или внешний CSS?
Зависит от общего размера CSS. Меньше 20 КиБ — встраивание выгоднее. Больше — вынесение во внешний файл с использованием кэша браузера значительно ускоряет последующие визиты.
Почему Google Fonts CDN работает медленно?
PageSpeed Insights симулирует медленный 4G (~1,6 Мбит/с, RTT 150 мс). Подключение к внешнему домену требует DNS-запрос + TCP-соединение + TLS-рукопожатие, и эта задержка блокирует рендеринг. Самостоятельное размещение устраняет эту задержку, обслуживая шрифты с того же домена.
Что делать, если wsrv.nl работает медленно?
wsrv.nl обслуживается через Cloudflare CDN и обычно работает быстро. Однако если кэш CDN промахивается во время тестирования PageSpeed, LCP может ухудшиться. Установите <link rel="preload"> для критически важных изображений, чтобы дать браузеру команду загрузить их заранее.
Влияет ли ленивая загрузка AdSense на доход?
Если в первом экране нет рекламы, загрузка при первой прокрутке даёт практически такое же время показа. Преимущества SEO от повышения скорости страницы оказывают более положительное влияние.
G

Gui

Генеральный директор Acecore. Универсальный инженер, охватывающий разработку систем, веб-производство, управление инфраструктурой и IT-образование. Любит решать организационные и человеческие задачи с помощью технологий.

Разработка систем Веб-производство Управление инфраструктурой IT-образование

Хотите узнать больше о наших услугах?

Мы обеспечиваем комплексную поддержку: разработка систем, веб-дизайн, графический дизайн и IT-образование.

Похожие статьи

Поиск статей