Astro 5 Islands: SEO-лендинг с View Transitions — KEL IT
Сайты 8 мин чтения

Astro 5 Islands: SEO-лендинг с View Transitions

Маркетинговый сайт из пяти–десяти страниц — классический кейс, где React- или Vue-SPA проигрывает по Core Web Vitals: весь фреймворк грузится ради одной кнопки «Записаться». SSR на Next.js решает SEO, но TTFB растёт, а edge-кэш сложнее настроить. Astro 5 предлагает другой компромисс: HTML генерируется статически, JavaScript подключается точечно — только к «островам» (Islands), которым нужна интерактивность.

В Astro 5 появились View Transitions — плавные переходы между страницами без полноценного SPA. Пользователь видит анимацию смены экрана, поисковый робот — обычный HTML с уникальным <title> и canonical на каждой странице. Это не противоречие: View Transitions работают поверх MPA (multi-page application), а не заменяют его.

В статье соберём production-лендинг услуг: главная, прайс, контакты, форма с shadcn/ui через React-island, hero с framer-motion, JSON-LD и деплой на Vercel.

Зачем Islands на лендинге, а не SPA или SSR

Архитектура Islands — главная идея Astro. Сервер (или сборщик) отдаёт чистый HTML. Компоненты с директивой client:* гидратируются изолированно; остальная страница остаётся статической разметкой без JavaScript.

ПодходJS на первом экранеSEOПереходы между страницами
SPA (React/Vite)Весь бандлТребует SSR/prerenderМгновенные, но тяжёлые
SSR (Next.js)Зависит от RSC/CSRОтличныйНавигация через router
Astro IslandsТолько островаПолный HTML из коробкиMPA + View Transitions

Для лендинга услуг типичное распределение:

Без JavaScript (статический HTML):

  • Hero с заголовком, подзаголовком, текстом CTA
  • Блок преимуществ, отзывы, FAQ
  • Footer, навигация, breadcrumbs
  • Open Graph, canonical, JSON-LD

С JavaScript (Islands):

  • Форма записи с валидацией (React + shadcn/ui)
  • Калькулятор стоимости
  • Анимированный hero (framer-motion)
  • Cookie-баннер, A/B-блок по UTM

Lighthouse на такой схеме стабильно даёт LCP < 1.5 s и TBT близкий к нулю, потому что основной контент не ждёт гидратации.

Структура проекта Astro 5

Создаём проект с React-интеграцией — для shadcn/ui и framer-motion:

npm create astro@latest landing -- --template basics
cd landing
npx astro add react
npx astro add tailwind

Типичная структура лендинга:

src/
├── layouts/
│   └── BaseLayout.astro      # <head>, View Transitions, JSON-LD
├── pages/
│   ├── index.astro           # главная
│   ├── pricing.astro         # прайс
│   └── contact.astro         # контакты + форма
├── components/
│   ├── Hero.astro            # статический hero
│   ├── HeroAnimation.tsx     # framer-motion island
│   ├── BookingForm.tsx       # React island
│   └── Faq.astro
└── content/
    └── services/             # Content Layer (опционально)
        └── web-dev.md

Базовый layout с View Transitions:

---
// src/layouts/BaseLayout.astro
import { ViewTransitions } from 'astro:transitions';

interface Props {
  title: string;
  description: string;
}

const { title, description } = Astro.props;
const canonical = new URL(Astro.url.pathname, Astro.site);
---

<html lang="ru">
  <head>
    <meta charset="utf-8" />
    <meta name="description" content={description} />
    <link rel="canonical" href={canonical} />
    <title>{title}</title>
    <ViewTransitions />
  </head>
  <body>
    <slot />
  </body>
</html>

ViewTransitions вставляет клиентский скрипт (~2 KB gzip), который перехватывает клики по внутренним ссылкам и анимирует смену DOM. При отключённом JS браузер работает как обычный MPA — SEO не страдает.

Если нужна подобная разработка — напишите в Telegram.

View Transitions: анимация без SPA

View Transitions API изначально появился в браузерах; Astro 5 оборачивает его в <ViewTransitions /> и даёт fallback для Safari через @astrojs/transitions. Переходы настраиваются на уровне layout или отдельных элементов.

Именованные переходы для hero-секции

Чтобы hero плавно морфился между главной и прайсом, помечаем элемент transition:name:

---
// src/pages/index.astro
import BaseLayout from '../layouts/BaseLayout.astro';
---

<BaseLayout title="Разработка сайтов — Astro, Next.js" description="...">
  <header transition:name="hero" transition:animate="fade">
    <h1>Быстрые SEO-лендинги</h1>
  </header>
  <!-- остальной контент -->
</BaseLayout>
---
// src/pages/pricing.astro
---
<BaseLayout title="Цены — разработка сайтов" description="...">
  <header transition:name="hero" transition:animate="fade">
    <h1>Тарифы</h1>
  </header>
</BaseLayout>

Одинаковый transition:name="hero" связывает элементы на разных страницах — браузер интерполирует позицию и размер. Для SEO каждая страница сохраняет свой <h1> и уникальный title; робот индексирует их независимо.

Prefetch для мгновенного ощущения

Astro 5 prefetch загружает HTML соседних страниц при наведении на ссылку:

<a href="/pricing" data-astro-prefetch>Цены</a>

Prefetch не подгружает JavaScript островов заранее — только HTML. Это сохраняет экономию трафика и не ухудшает INP на текущей странице.

Islands: React, shadcn/ui и framer-motion

Директива client:visible — оптимальный выбор для форм и анимаций ниже первого экрана: JS загружается, когда блок попадает во viewport.

---
// src/pages/contact.astro
import BookingForm from '../components/BookingForm.tsx';
---

<section id="booking">
  <h2>Записаться на консультацию</h2>
  <BookingForm client:visible />
</section>

Для hero-анимации на первом экране используем client:load — компонент гидратируется сразу, но изолирован от остальной страницы:

---
import HeroAnimation from '../components/HeroAnimation.tsx';
---

<HeroAnimation client:load />
// src/components/HeroAnimation.tsx
import { motion } from 'framer-motion';

export default function HeroAnimation() {
  return (
    <motion.div
      initial={{ opacity: 0, y: 20 }}
      animate={{ opacity: 1, y: 0 }}
      transition={{ duration: 0.6 }}
    >
      {/* декоративные элементы — не SEO-критичный контент */}
    </motion.div>
  );
}

Важно для SEO: текст заголовка и описания держим в .astro-файле, а не внутри framer-motion. Анимация — декоративный слой; робот читает статический HTML.

shadcn/ui подключается как обычный React-компонент в island. Tailwind-конфиг общий для Astro и React — классы не дублируются.

Content Layer для FAQ и кейсов

Astro 5 Content Layer позволяет хранить тексты в Markdown/MDX и генерировать статические страницы:

// src/content.config.ts
import { defineCollection, z } from 'astro:content';

const faq = defineCollection({
  type: 'content',
  schema: z.object({
    question: z.string(),
    order: z.number(),
  }),
});

export const collections = { faq };

Контент рендерится в HTML при сборке — идеально для FAQ-блоков, которые должны попасть в индекс без client-side fetch.

SEO: metadata, JSON-LD и Core Web Vitals

View Transitions не меняют правила SEO — они лишь улучшают UX. Базовый чеклист остаётся прежним.

Уникальные meta на каждой странице

Каждый .astro-файл передаёт title и description в layout. Canonical строится из Astro.site + pathname — дубликаты не попадают в индекс.

JSON-LD для услуг

Structured data — Server-side в Astro по умолчанию:

---
const schema = {
  '@context': 'https://schema.org',
  '@type': 'ProfessionalService',
  name: 'Разработка сайтов',
  url: Astro.site,
  areaServed: 'RU',
};
---

<script type="application/ld+json" set:html={JSON.stringify(schema)} />

JSON-LD в <head> или перед </body> — в статическом HTML, виден Googlebot без JavaScript.

Core Web Vitals: что проверять

МетрикаЦельКак Astro помогает
LCP< 2.5 sСтатический HTML, без блокирующего JS
INP< 200 msIslands не блокируют main thread целиком
CLS< 0.1Резерв места под island через skeleton

PageSpeed Insights: прогоняйте каждую страницу отдельно (/, /pricing, /contact). View Transitions влияют только на клиентскую навигацию — первый заход оценивается как обычный MPA.

Google Search Console: «Проверка URL» покажет rendered HTML. Убедитесь, что <title>, canonical и тексты FAQ видны в снимке.

Деплой на Vercel и preview-окружения

Astro 5 деплоится на Vercel одной командой:

npm run build
# output: dist/

Vercel определяет Astro автоматически. Статические файлы раздаются с Edge Network; vercel.json для редиректов или заголовков безопасности:

{
  "headers": [
    {
      "source": "/(.*)",
      "headers": [
        { "key": "X-Content-Type-Options", "value": "nosniff" }
      ]
    }
  ]
}

Preview-деплои на каждый PR — удобно проверять View Transitions и Lighthouse до merge. Production URL отдаёт Cache-Control для статики; HTML страниц кэшируется на edge после деплоя.

Альтернатива — Cloudflare Pages или Netlify. Islands-архитектура одинаково работает везде, где есть static hosting.

Нужна помощь? Telegram → или vic.kell@ya.ru

FAQ

View Transitions ломают SEO и индексацию?

Нет. Каждая страница — отдельный HTML-документ с уникальным URL, title и canonical. View Transitions активируются только при клиентской навигации. Googlebot получает полный HTML при первом запросе; prefetch не меняет canonical.

Когда Islands хуже, чем Next.js 15 с PPR?

Если нужна одна страница с несколькими динамическими блоками (форма + калькулятор + персонализация по cookie) и команда уже на React — Next.js 15 с Partial Prerendering может быть проще. Astro выигрывает на многостраничных маркетинговых сайтах, где большинство контента статично.

Можно ли подключить headless CMS?

Да. Sanity, Contentful, Strapi — fetch на этапе сборки (getStaticPaths / Content Layer). Контент попадает в HTML; revalidate через webhook + CI redeploy или @astrojs/vercel с ISR-подобным поведением на adapter-уровне.

client:visible или client:idle для формы?

client:visible — для блоков ниже fold: экономит JS на первом экране. client:idle — если форма в hero и должна быть интерактивной быстро, но не блокировать LCP. Избегайте client:only на SEO-критичном контенте — он не рендерится на сервере.

framer-motion не убивает INP?

Изолированный island с framer-motion не блокирует гидратацию всей страницы. Держите анимацию декоративной, используйте will-change умеренно, тестируйте INP в Chrome DevTools Performance. Текст hero — в статическом Astro, не в motion-компоненте.

Заключение

Astro 5 с Islands и View Transitions — сильная связка для SEO-лендингов и небольших маркетинговых сайтов. Статический HTML обеспечивает индексацию и высокие Core Web Vitals; JavaScript подключается точечно к формам и анимациям. View Transitions дают SPA-подобный UX без SPA-оверхеда.

Практическая схема: тексты и SEO-разметка в .astro, интерактив в React-islands с client:visible / client:load, JSON-LD в layout, деплой статики на Vercel. Для одностраничного лендинга с тяжёлой динамикой смотрите Next.js 15 PPR — для классического многостраничного сайта Astro остаётся более лёгким выбором в 2026 году.

KEL IT

Нужна разработка под ключ?

Я занимаюсь такими проектами профессионально. Telegram-боты, Mini Apps, сайты, мобильные и десктопные приложения. Расскажите о задаче — разберём и предложим решение.