AstroJuniorCoding

Что такое layouts в Astro и как они используются со свойством layout во frontmatter?

Layout в Astro — компонент с <slot />, который оборачивает контент страниц; в .md/.mdx файлах он указывается через свойство layout во frontmatter, и тогда всё содержимое Markdown подставляется в слот.

Layouts в Astro

Layout в Astro — это обычный .astro-компонент, который оборачивает контент страниц. Он содержит повторяющиеся элементы: <html>, <head>, навигацию, футер. Дочерний контент вставляется через компонент <slot />.

Создание layout-компонента

---
// src/layouts/BaseLayout.astro
const { title, description = 'Мой сайт' } = Astro.props;
---

<!DOCTYPE html>
<html lang="ru">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width" />
    <meta name="description" content={description} />
    <title>{title}</title>
  </head>
  <body>
    <nav>...</nav>
    <main>
      <slot />  <!-- Сюда подставляется контент страницы -->
    </main>
    <footer>...</footer>
  </body>
</html>

Использование layout в .astro-странице

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

<BaseLayout title="О нас" description="Страница о компании">
  <h1>О нас</h1>
  <p>Добро пожаловать!</p>
</BaseLayout>

Использование layout в Markdown через frontmatter

В .md и .mdx файлах layout указывается в свойстве layout во frontmatter. Astro автоматически оборачивает содержимое файла в указанный компонент.

---
# src/content/blog/my-post.md
layout: ../../layouts/BlogPostLayout.astro
title: Мой первый пост
date: 2024-01-15
author: Иван Иванов
---

# Заголовок поста

Текст статьи в формате Markdown.

Layout для Markdown получает все frontmatter-данные через Astro.props.frontmatter:

---
// src/layouts/BlogPostLayout.astro
const { frontmatter } = Astro.props;
// frontmatter.title, frontmatter.date, frontmatter.author
---

<html lang="ru">
  <head>
    <title>{frontmatter.title}</title>
  </head>
  <body>
    <article>
      <h1>{frontmatter.title}</h1>
      <time>{frontmatter.date}</time>
      <slot />  <!-- Отрендеренный Markdown попадёт сюда -->
    </article>
  </body>
</html>

Именованные слоты

Layout может содержать несколько именованных слотов:

---
// src/layouts/TwoColumn.astro
---
<div class="layout">
  <aside><slot name="sidebar" /></aside>
  <main><slot /><!-- default slot --></main>
</div>
---
// src/pages/dashboard.astro
import TwoColumn from '../layouts/TwoColumn.astro';
---

<TwoColumn>
  <nav slot="sidebar">Навигация</nav>
  <h1>Главный контент</h1>
</TwoColumn>

Вложенные layouts

Layouts можно вкладывать: BlogLayout использует BaseLayout внутри себя, создавая иерархию шаблонов.

Подводные камни

  • frontmatter.layout — строка-путь, не импорт — в Markdown нужно указывать относительный путь к файлу, а не имя компонента; неверный путь приведёт к ошибке сборки.
  • Astro.props.frontmatter только в Markdown-layouts — в обычных страницах frontmatter в props не приходит; данные передаются явно через атрибуты.
  • Дублирование тега html — если layout уже содержит <html>, а страница тоже добавляет его через другой layout, получится невалидный HTML.
  • Слот по умолчанию без имени — содержимое без slot="name" попадает в <slot /> без атрибута; если его нет в layout, контент будет проигнорирован.
  • Styles в layout применяются глобально<style> внутри layout без is:global всё равно scoped; для глобальных стилей нужен <style is:global>.
  • MDX и layout — в .mdx файлах можно также экспортировать export const layout вместо frontmatter, но два подхода одновременно конфликтуют.

Common mistakes

  • Ждать, что layout во frontmatter сработает для Content Collections.
  • Не использовать именованные слоты и копировать одинаковую структуру.
  • Тащить бизнес-логику в layout, делая его непредсказуемым.

What the interviewer is testing

  • Знает, что layout это обычный .astro со <slot />.
  • Различает применение в .astro и в Markdown frontmatter.
  • Понимает ограничения для Content Collections.

Sources

Related topics