Практические техники достижения 99 баллов PageSpeed Mobile на сайте Astro
Содержание
- Введение
- Почему Astro?
- Стратегия доставки CSS: встроенный vs внешний
- Когда CSS небольшой (~20 КиБ)
- Когда CSS большой (20 КиБ+)
- Решение: вынесение во внешний файл + неизменяемый кэш
- Оптимизация шрифтов: правильная настройка самостоятельного размещения
- Избегайте Google Fonts CDN
- Внедрение самостоятельного размещения
- Осторожно: несоответствие имени шрифта
- Оптимизация изображений: wsrv.nl + srcset + sizes
- Прокси wsrv.nl
- Настройка srcset и sizes
- Точность sizes
- Улучшение LCP: preload
- Предотвращение CLS (сдвиг макета)
- Ленивая загрузка рекламы и аналитики
- AdSense
- GA4
- Стратегия кэширования
- Чек-лист оптимизации производительности
- Заключение
- Серия статей
Введение
Официальный сайт Acecore построен на Astro 6 + UnoCSS + Cloudflare Pages. В этой статье представлены техники оптимизации, использованные для достижения Mobile 99 / Desktop 100 в PageSpeed Insights.
Достигнутые итоговые оценки:
| Метрика | Mobile | Desktop |
|---|---|---|
| Performance | 99 | 100 |
| Accessibility | 100 | 100 |
| Best Practices | 100 | 100 |
| SEO | 100 | 100 |
Почему 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 всегда запрашивает последнюю версию
Чек-лист оптимизации производительности
- Правильна ли стратегия доставки CSS?: встраивание ниже 20 КиБ, вынесение выше
- Размещены ли шрифты на своём сервере?: внешний CDN губителен на медленном 4G
- Правильно ли имя шрифта?: проверьте зарегистрированное имя
@fontsource-variable(*Variable) - Есть ли у всех изображений srcset + sizes?: особенно подготовьте меньшие размеры для мобильных
- Есть ли preload у элемента LCP?: изображения на главном экране и изображения первого экрана
- Указаны ли width/height у изображений?: предотвращение CLS
- Загружаются ли AdSense/GA4 лениво?: нулевая передача JS при первом показе
- Настроены ли заголовки кэширования?: неизменяемый кэш для ускорения последующих визитов
Заключение
Принцип оптимизации производительности можно выразить одной фразой: «Не отправляйте лишнее». Встраивание 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?
Почему Google Fonts CDN работает медленно?
Что делать, если wsrv.nl работает медленно?
Влияет ли ленивая загрузка AdSense на доход?
Gui
Генеральный директор Acecore. Универсальный инженер, охватывающий разработку систем, веб-производство, управление инфраструктурой и IT-образование. Любит решать организационные и человеческие задачи с помощью технологий.
Хотите узнать больше о наших услугах?
Мы обеспечиваем комплексную поддержку: разработка систем, веб-дизайн, графический дизайн и IT-образование.