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

Портфолио на Astro: Пошаговый гайд для разработчика и дизайнера

Как создать профессиональное портфолио на Astro.js: структура проекта, анимации, галерея работ, форма контакта, деплой. Примеры кода и советы по дизайну.

person
Журналист
Автор
Портфолио на Astro — гайд для разработчика и дизайнера

Портфолио — визитная карточка разработчика или дизайнера. Оно должно загружаться мгновенно, выглядеть безупречно и демонстрировать техническую экспертизу. Astro — идеальный выбор: нулевой JS по умолчанию, PageSpeed 100, поддержка анимаций через Vue/React/Svelte острова.

Почему Astro для портфолио?

  • PageSpeed 100 — потенциальный работодатель откроет Lighthouse и увидит идеал
  • View Transitions API — плавные переходы между страницами без SPA
  • Бесплатный хостинг — Cloudflare Pages, Vercel, Netlify
  • Минимум зависимостей — никаких тяжелых фреймворков для статичных страниц
  • TypeScript — демонстрирует серьёзность подхода

Структура портфолио

code
portfolio/
├── src/
│   ├── content/
│   │   └── projects/        # Описания проектов в MDX
│   │       ├── project-1.mdx
│   │       └── project-2.mdx
│   ├── components/
│   │   ├── Hero.astro        # Главный экран с именем
│   │   ├── ProjectCard.astro # Карточка проекта
│   │   ├── SkillsGrid.astro  # Сетка технологий
│   │   └── ContactForm.tsx   # Форма (Preact-остров)
│   └── pages/
│       ├── index.astro       # Главная (Hero + Проекты + Навыки)
│       ├── projects/
│       │   ├── index.astro   # Все проекты
│       │   └── [slug].astro  # Детальная страница проекта
│       └── contact.astro     # Контакты

Content Collection для проектов

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

const projects = defineCollection({
  loader: glob({ pattern: '**/*.mdx', base: './src/content/projects' }),
  schema: ({ image }) =>
    z.object({
      title: z.string(),
      description: z.string(),
      tags: z.array(z.string()), // React, TypeScript, Astro...
      cover: image().optional(),
      url: z.string().url().optional(), // Ссылка на живой проект
      github: z.string().url().optional(), // Ссылка на репозиторий
      date: z.coerce.date(),
      featured: z.boolean().default(false), // Показывать на главной
    }),
});

export const collections = { projects };

Frontmatter проекта

code
---
title: 'E-commerce платформа для ювелирного бренда'
description: 'Разработал интернет-магазин с нуля: Astro + PocketBase + Stripe'
tags: ['Astro', 'TypeScript', 'PocketBase', 'Stripe', 'TailwindCSS']
url: 'https://jewelry-store.example.com'
github: 'https://github.com/username/jewelry-store'
date: 2026-03-15
featured: true
---

## О проекте

Клиент — небольшой ювелирный бренд, которому нужен был магазин...

Hero-секция с анимацией

Используйте View Transitions для плавности без JavaScript-фреймворка:

code
---
// src/components/Hero.astro
---

<section class="hero">
  <div class="hero__content">
    <p class="hero__greeting">Привет, меня зовут</p>
    <h1 class="hero__name" transition:name="name">Иван Иванов</h1>
    <h2 class="hero__role">Frontend-разработчик</h2>
    <p class="hero__bio">
      Строю быстрые, доступные веб-сайты на Astro, React и TypeScript. Специализируюсь на
      контентных проектах и e-commerce.
    </p>
    <div class="hero__cta">
      <a href="/projects/" class="btn btn--primary">Мои работы</a>
      <a href="/contact/" class="btn btn--outline">Написать</a>
    </div>
  </div>
</section>

Галерея проектов

code
---
// src/pages/index.astro
import { getCollection } from 'astro:content';
import { Image } from 'astro:assets';
import ProjectCard from '../components/ProjectCard.astro';

const allProjects = await getCollection('projects');
const featuredProjects = allProjects
  .filter((p) => p.data.featured)
  .sort((a, b) => b.data.date.getTime() - a.data.date.getTime());
---

<section>
  <h2>Избранные проекты</h2>
  <div class="projects-grid">
    {
      featuredProjects.map((project) => (
        <ProjectCard
          title={project.data.title}
          description={project.data.description}
          tags={project.data.tags}
          url={project.data.url}
          slug={project.id.replace('.mdx', '')}
          cover={project.data.cover}
        />
      ))
    }
  </div>
  <a href="/projects/">Все проекты →</a>
</section>

Секция навыков

code
---
// src/components/SkillsGrid.astro
const skills = [
  { category: 'Frontend', items: ['Astro', 'React', 'TypeScript', 'TailwindCSS'] },
  { category: 'Backend', items: ['Node.js', 'PocketBase', 'PostgreSQL', 'Redis'] },
  { category: 'DevOps', items: ['Docker', 'Nginx', 'Cloudflare', 'GitHub Actions'] },
  { category: 'Инструменты', items: ['Figma', 'Git', 'Vite', 'Vitest'] },
];
---

<section>
  <h2>Технологии</h2>
  <div class="skills-grid">
    {
      skills.map((group) => (
        <div class="skill-group">
          <h3>{group.category}</h3>
          <ul>
            {group.items.map((skill) => (
              <li>
                <span class="badge">{skill}</span>
              </li>
            ))}
          </ul>
        </div>
      ))
    }
  </div>
</section>
animation

View Transitions

Добавьте &lt;ViewTransitions /&gt; в BaseLayout. Переходы между страницами портфолио станут плавными — как в SPA, но без React.

bar_chart

Метрики проектов

В описании каждого проекта добавьте конкретные числа: «Скорость загрузки выросла на 340%», «Конверсия +12%».

dark_mode

Dark Mode

Реализуйте через CSS prefers-color-scheme и маленький Preact-остров для ручного переключения. Хранить выбор — в localStorage.

Форма контакта

code
// src/components/ContactForm.tsx (Preact-остров)
import { useState } from 'preact/hooks';

export default function ContactForm() {
  const [status, setStatus] = useState<'idle' | 'loading' | 'success' | 'error'>('idle');

  async function handleSubmit(e: Event) {
    e.preventDefault();
    setStatus('loading');
    const form = e.target as HTMLFormElement;
    const data = Object.fromEntries(new FormData(form));

    try {
      await fetch('/api/contact', {
        method: 'POST',
        body: JSON.stringify(data),
        headers: { 'Content-Type': 'application/json' },
      });
      setStatus('success');
    } catch {
      setStatus('error');
    }
  }

  return (
    <form onSubmit={handleSubmit}>
      <input name="name" placeholder="Ваше имя" required />
      <input name="email" type="email" placeholder="Email" required />
      <textarea name="message" placeholder="Расскажите о проекте" rows={5} required />
      <button type="submit" disabled={status === 'loading'}>
        {status === 'loading' ? 'Отправка...' : 'Отправить'}
      </button>
      {status === 'success' && <p>Сообщение отправлено!</p>}
    </form>
  );
}

В contact.astro:

code
---
import ContactForm from '../components/ContactForm.tsx';
---

<ContactForm client:load />

SEO для портфолио

Особое внимание — structured data Person:

code
---
const personSchema = {
  '@context': 'https://schema.org',
  '@type': 'Person',
  name: 'Иван Иванов',
  jobTitle: 'Frontend Developer',
  url: 'https://ivanivanov.ru',
  sameAs: [
    'https://github.com/ivanivanov',
    'https://linkedin.com/in/ivanivanov',
    'https://t.me/ivanivanov',
  ],
  knowsAbout: ['Astro', 'React', 'TypeScript', 'Web Development'],
};
---

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

Деплой и домен

Бесплатные варианты:

  • Cloudflare Pagesyourname.pages.dev или свой домен
  • GitHub Pagesusername.github.io
  • Vercelyourname.vercel.app

Для профессионального портфолио рекомендуем купить домен имяфамилия.ru (~150 руб/год). Инструкция по деплою — в статье Деплой и хостинг для Astro.

Итог

Портфолио на Astro — это заявление о вашей технической зрелости. PageSpeed 100, плавные View Transitions, строгая типизация проектов через Content Collections — всё это говорит о вас больше, чем любое резюме. Потратьте выходные — получите визитку, которая работает на вас круглосуточно.

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

Senior Frontend Engineer / Tech Writer

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

Комментарии

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

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

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

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