Перейти к содержимому

2. CSS Portfolio

Построй стильное портфолио с адаптивным дизайном и темной темой за 2-3 часа.

Personal Portfolio Website — твоя визитная карточка в интернете.

Основные секции:

  • Header с переключателем темы
  • About Me (О себе)
  • Skills (Навыки с прогресс-барами)
  • Projects (Проекты в сетке)
  • Contact Form (Форма связи)

Что вы освоите:

  • CSS Grid и Flexbox
  • CSS Custom Properties (переменные)
  • Темная/светлая тема
  • Адаптивный дизайн
  • CSS Animations

Окно терминала
mkdir css-portfolio
cd css-portfolio

Создай три файла:

  • index.html — разметка
  • styles.css — стили
  • script.js — переключатель темы (минимальный JS)

<!DOCTYPE html>
<html lang="ru" data-theme="light">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="Portfolio of Alex Smith - Full-stack Developer">
<title>Alex Smith | Portfolio</title>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<!-- Header -->
<header class="header">
<div class="container">
<nav class="nav">
<a href="#" class="logo">AS</a>
<ul class="nav-menu">
<li><a href="#about">About</a></li>
<li><a href="#skills">Skills</a></li>
<li><a href="#projects">Projects</a></li>
<li><a href="#contact">Contact</a></li>
</ul>
<button class="theme-toggle" id="themeToggle" aria-label="Toggle theme">
<span class="sun">☀️</span>
<span class="moon">🌙</span>
</button>
</nav>
</div>
</header>
<!-- Hero / About -->
<section id="about" class="hero">
<div class="container">
<div class="hero-content">
<div class="hero-text">
<h1 class="hero-title">
Hi, I'm <span class="gradient-text">Alex Smith</span>
</h1>
<p class="hero-subtitle">Full-stack Developer</p>
<p class="hero-description">
I build modern web applications with React, Node.js, and TypeScript.
Passionate about clean code and great user experience.
</p>
<div class="hero-cta">
<a href="#projects" class="btn btn-primary">View Projects</a>
<a href="#contact" class="btn btn-outline">Get in Touch</a>
</div>
</div>
<div class="hero-image">
<div class="avatar">
<div class="avatar-placeholder">AS</div>
</div>
</div>
</div>
</div>
</section>
<!-- Skills -->
<section id="skills" class="skills">
<div class="container">
<h2 class="section-title">Skills & Technologies</h2>
<div class="skills-grid">
<div class="skill-category">
<h3>Frontend</h3>
<div class="skill-item">
<div class="skill-name">React / Next.js</div>
<div class="skill-bar">
<div class="skill-progress" style="--progress: 90%"></div>
</div>
</div>
<div class="skill-item">
<div class="skill-name">TypeScript</div>
<div class="skill-bar">
<div class="skill-progress" style="--progress: 85%"></div>
</div>
</div>
<div class="skill-item">
<div class="skill-name">CSS / Tailwind</div>
<div class="skill-bar">
<div class="skill-progress" style="--progress: 95%"></div>
</div>
</div>
</div>
<div class="skill-category">
<h3>Backend</h3>
<div class="skill-item">
<div class="skill-name">Node.js / Express</div>
<div class="skill-bar">
<div class="skill-progress" style="--progress: 80%"></div>
</div>
</div>
<div class="skill-item">
<div class="skill-name">PostgreSQL / MongoDB</div>
<div class="skill-bar">
<div class="skill-progress" style="--progress: 75%"></div>
</div>
</div>
<div class="skill-item">
<div class="skill-name">REST API / GraphQL</div>
<div class="skill-bar">
<div class="skill-progress" style="--progress: 85%"></div>
</div>
</div>
</div>
<div class="skill-category">
<h3>Tools</h3>
<div class="skill-item">
<div class="skill-name">Git / GitHub</div>
<div class="skill-bar">
<div class="skill-progress" style="--progress: 90%"></div>
</div>
</div>
<div class="skill-item">
<div class="skill-name">Docker</div>
<div class="skill-bar">
<div class="skill-progress" style="--progress: 70%"></div>
</div>
</div>
<div class="skill-item">
<div class="skill-name">CI/CD</div>
<div class="skill-bar">
<div class="skill-progress" style="--progress: 75%"></div>
</div>
</div>
</div>
</div>
</div>
</section>
<!-- Projects -->
<section id="projects" class="projects">
<div class="container">
<h2 class="section-title">Featured Projects</h2>
<div class="projects-grid">
<!-- Project 1 -->
<article class="project-card">
<div class="project-image">
<div class="project-placeholder">E-Commerce</div>
</div>
<div class="project-content">
<h3>E-Commerce Platform</h3>
<p>
Full-stack online store with payment integration,
admin dashboard, and real-time inventory management.
</p>
<div class="project-tags">
<span class="tag">React</span>
<span class="tag">Node.js</span>
<span class="tag">Stripe</span>
</div>
<div class="project-links">
<a href="#" class="project-link">Live Demo</a>
<a href="#" class="project-link">GitHub</a>
</div>
</div>
</article>
<!-- Project 2 -->
<article class="project-card">
<div class="project-image">
<div class="project-placeholder">Task Manager</div>
</div>
<div class="project-content">
<h3>Task Management App</h3>
<p>
Collaborative task manager with drag-and-drop,
real-time updates, and team workspaces.
</p>
<div class="project-tags">
<span class="tag">Next.js</span>
<span class="tag">PostgreSQL</span>
<span class="tag">WebSockets</span>
</div>
<div class="project-links">
<a href="#" class="project-link">Live Demo</a>
<a href="#" class="project-link">GitHub</a>
</div>
</div>
</article>
<!-- Project 3 -->
<article class="project-card">
<div class="project-image">
<div class="project-placeholder">Portfolio</div>
</div>
<div class="project-content">
<h3>Weather Dashboard</h3>
<p>
Real-time weather app with forecasts,
interactive maps, and location search.
</p>
<div class="project-tags">
<span class="tag">TypeScript</span>
<span class="tag">OpenWeather API</span>
<span class="tag">Charts.js</span>
</div>
<div class="project-links">
<a href="#" class="project-link">Live Demo</a>
<a href="#" class="project-link">GitHub</a>
</div>
</div>
</article>
</div>
</div>
</section>
<!-- Contact -->
<section id="contact" class="contact">
<div class="container">
<h2 class="section-title">Get In Touch</h2>
<p class="section-subtitle">
Have a project in mind? Let's work together.
</p>
<form class="contact-form">
<div class="form-group">
<label for="name">Name</label>
<input type="text" id="name" name="name" required>
</div>
<div class="form-group">
<label for="email">Email</label>
<input type="email" id="email" name="email" required>
</div>
<div class="form-group">
<label for="message">Message</label>
<textarea id="message" name="message" rows="5" required></textarea>
</div>
<button type="submit" class="btn btn-primary">Send Message</button>
</form>
</div>
</section>
<!-- Footer -->
<footer class="footer">
<div class="container">
<p>&copy; 2026 Alex Smith. Built with HTML & CSS.</p>
<div class="footer-links">
<a href="#">GitHub</a>
<a href="#">LinkedIn</a>
<a href="#">Twitter</a>
</div>
</div>
</footer>
<script src="script.js"></script>
</body>
</html>

:root {
/* Light theme colors */
--bg-primary: #ffffff;
--bg-secondary: #f8f9fa;
--bg-tertiary: #e9ecef;
--text-primary: #212529;
--text-secondary: #6c757d;
--accent: #6366f1;
--accent-hover: #4f46e5;
--border: #dee2e6;
--shadow: rgba(0, 0, 0, 0.1);
/* Spacing */
--spacing-xs: 0.5rem;
--spacing-sm: 1rem;
--spacing-md: 2rem;
--spacing-lg: 4rem;
--spacing-xl: 6rem;
/* Typography */
--font-body: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
--font-heading: 'Inter', var(--font-body);
}
[data-theme="dark"] {
--bg-primary: #1a1a1a;
--bg-secondary: #2d2d2d;
--bg-tertiary: #3a3a3a;
--text-primary: #f8f9fa;
--text-secondary: #adb5bd;
--accent: #818cf8;
--accent-hover: #6366f1;
--border: #3a3a3a;
--shadow: rgba(0, 0, 0, 0.3);
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
html {
scroll-behavior: smooth;
}
body {
font-family: var(--font-body);
background: var(--bg-primary);
color: var(--text-primary);
line-height: 1.6;
transition: background 0.3s ease, color 0.3s ease;
}
.container {
max-width: 1200px;
margin: 0 auto;
padding: 0 var(--spacing-sm);
}
.section-title {
font-size: 2.5rem;
text-align: center;
margin-bottom: var(--spacing-sm);
font-weight: 700;
}
.section-subtitle {
text-align: center;
color: var(--text-secondary);
margin-bottom: var(--spacing-lg);
font-size: 1.125rem;
}
.header {
background: var(--bg-primary);
border-bottom: 1px solid var(--border);
position: sticky;
top: 0;
z-index: 1000;
transition: all 0.3s ease;
}
.nav {
display: flex;
justify-content: space-between;
align-items: center;
padding: var(--spacing-sm) 0;
}
.logo {
font-size: 1.5rem;
font-weight: 700;
color: var(--accent);
text-decoration: none;
}
.nav-menu {
display: flex;
list-style: none;
gap: var(--spacing-md);
}
.nav-menu a {
color: var(--text-primary);
text-decoration: none;
font-weight: 500;
transition: color 0.3s;
}
.nav-menu a:hover {
color: var(--accent);
}
.theme-toggle {
background: var(--bg-secondary);
border: 1px solid var(--border);
border-radius: 50px;
padding: 0.5rem 1rem;
cursor: pointer;
font-size: 1.25rem;
transition: all 0.3s;
display: flex;
align-items: center;
gap: 0.5rem;
}
.theme-toggle:hover {
background: var(--bg-tertiary);
}
[data-theme="light"] .moon {
display: none;
}
[data-theme="dark"] .sun {
display: none;
}
.hero {
padding: var(--spacing-xl) 0;
background: var(--bg-secondary);
}
.hero-content {
display: grid;
grid-template-columns: 1fr 1fr;
gap: var(--spacing-lg);
align-items: center;
}
.hero-title {
font-size: 3rem;
line-height: 1.2;
margin-bottom: var(--spacing-sm);
}
.gradient-text {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
}
.hero-subtitle {
font-size: 1.5rem;
color: var(--text-secondary);
margin-bottom: var(--spacing-sm);
}
.hero-description {
color: var(--text-secondary);
margin-bottom: var(--spacing-md);
font-size: 1.125rem;
}
.hero-cta {
display: flex;
gap: var(--spacing-sm);
}
.avatar {
width: 100%;
max-width: 400px;
aspect-ratio: 1;
display: flex;
align-items: center;
justify-content: center;
margin: 0 auto;
}
.avatar-placeholder {
width: 300px;
height: 300px;
border-radius: 50%;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
display: flex;
align-items: center;
justify-content: center;
font-size: 6rem;
color: #fff;
font-weight: 700;
box-shadow: 0 20px 60px var(--shadow);
}
.btn {
display: inline-block;
padding: 0.75rem 1.5rem;
border-radius: 8px;
text-decoration: none;
font-weight: 600;
transition: all 0.3s;
border: none;
cursor: pointer;
font-size: 1rem;
}
.btn-primary {
background: var(--accent);
color: #fff;
}
.btn-primary:hover {
background: var(--accent-hover);
transform: translateY(-2px);
box-shadow: 0 5px 20px rgba(99, 102, 241, 0.4);
}
.btn-outline {
background: transparent;
border: 2px solid var(--accent);
color: var(--accent);
}
.btn-outline:hover {
background: var(--accent);
color: #fff;
}
.skills {
padding: var(--spacing-xl) 0;
}
.skills-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: var(--spacing-lg);
}
.skill-category h3 {
font-size: 1.5rem;
margin-bottom: var(--spacing-md);
color: var(--accent);
}
.skill-item {
margin-bottom: var(--spacing-md);
}
.skill-name {
display: flex;
justify-content: space-between;
margin-bottom: 0.5rem;
font-weight: 500;
}
.skill-bar {
height: 8px;
background: var(--bg-tertiary);
border-radius: 4px;
overflow: hidden;
}
.skill-progress {
height: 100%;
background: linear-gradient(90deg, #667eea 0%, #764ba2 100%);
width: var(--progress);
border-radius: 4px;
transition: width 1s ease;
}
.projects {
padding: var(--spacing-xl) 0;
background: var(--bg-secondary);
}
.projects-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(350px, 1fr));
gap: var(--spacing-md);
}
.project-card {
background: var(--bg-primary);
border-radius: 12px;
overflow: hidden;
box-shadow: 0 4px 20px var(--shadow);
transition: transform 0.3s, box-shadow 0.3s;
}
.project-card:hover {
transform: translateY(-5px);
box-shadow: 0 10px 40px var(--shadow);
}
.project-image {
height: 200px;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
display: flex;
align-items: center;
justify-content: center;
}
.project-placeholder {
font-size: 2rem;
color: #fff;
font-weight: 700;
}
.project-content {
padding: var(--spacing-md);
}
.project-content h3 {
font-size: 1.5rem;
margin-bottom: var(--spacing-sm);
}
.project-content p {
color: var(--text-secondary);
margin-bottom: var(--spacing-sm);
}
.project-tags {
display: flex;
flex-wrap: wrap;
gap: 0.5rem;
margin-bottom: var(--spacing-sm);
}
.tag {
background: var(--bg-secondary);
color: var(--text-primary);
padding: 0.25rem 0.75rem;
border-radius: 20px;
font-size: 0.875rem;
font-weight: 500;
}
.project-links {
display: flex;
gap: var(--spacing-sm);
}
.project-link {
color: var(--accent);
text-decoration: none;
font-weight: 600;
}
.project-link:hover {
text-decoration: underline;
}
.contact {
padding: var(--spacing-xl) 0;
}
.contact-form {
max-width: 600px;
margin: 0 auto;
}
.form-group {
margin-bottom: var(--spacing-md);
}
.form-group label {
display: block;
margin-bottom: 0.5rem;
font-weight: 500;
}
.form-group input,
.form-group textarea {
width: 100%;
padding: 0.75rem;
border: 1px solid var(--border);
border-radius: 8px;
background: var(--bg-secondary);
color: var(--text-primary);
font-family: var(--font-body);
font-size: 1rem;
transition: border 0.3s;
}
.form-group input:focus,
.form-group textarea:focus {
outline: none;
border-color: var(--accent);
}
.contact-form .btn {
width: 100%;
}
.footer {
background: var(--bg-secondary);
padding: var(--spacing-md) 0;
text-align: center;
border-top: 1px solid var(--border);
}
.footer-links {
display: flex;
justify-content: center;
gap: var(--spacing-md);
margin-top: var(--spacing-sm);
}
.footer-links a {
color: var(--text-secondary);
text-decoration: none;
}
.footer-links a:hover {
color: var(--accent);
}
@media (max-width: 768px) {
.nav-menu {
display: none; /* Для простоты - в реальном проекте добавь мобильное меню */
}
.hero-content {
grid-template-columns: 1fr;
text-align: center;
}
.hero-title {
font-size: 2rem;
}
.hero-cta {
flex-direction: column;
}
.skills-grid {
grid-template-columns: 1fr;
}
.projects-grid {
grid-template-columns: 1fr;
}
}

// Theme toggle
const themeToggle = document.getElementById('themeToggle');
const html = document.documentElement;
// Check saved theme
const savedTheme = localStorage.getItem('theme') || 'light';
html.setAttribute('data-theme', savedTheme);
themeToggle.addEventListener('click', () => {
const currentTheme = html.getAttribute('data-theme');
const newTheme = currentTheme === 'light' ? 'dark' : 'light';
html.setAttribute('data-theme', newTheme);
localStorage.setItem('theme', newTheme);
});
// Smooth scroll
document.querySelectorAll('a[href^="#"]').forEach(anchor => {
anchor.addEventListener('click', function (e) {
e.preventDefault();
const target = document.querySelector(this.getAttribute('href'));
if (target) {
target.scrollIntoView({
behavior: 'smooth',
block: 'start'
});
}
});
});
// Form submission (placeholder)
const contactForm = document.querySelector('.contact-form');
contactForm.addEventListener('submit', (e) => {
e.preventDefault();
alert('Form submitted! (This is a demo - integrate with backend)');
});

Netlify / Vercel:

  1. Перетащи папку на Netlify Drop Zone
  2. Или используй Git:
    Окно терминала
    git init
    git add .
    git commit -m "Initial commit"
    git push
  3. Подключи репозиторий к Netlify/Vercel

GitHub Pages:

Окно терминала
# В настройках репозитория: Settings → Pages → Source: main branch

Animations:

  • Добавь @keyframes для fade-in при скролле
  • Анимируй skill bars при появлении в viewport

Интерактивность:

  • Мобильное меню (hamburger)
  • Фильтр проектов по технологиям
  • Форма с реальной отправкой (Formspree, EmailJS)

SEO:

  • Meta tags (Open Graph, Twitter Cards)
  • Sitemap.xml
  • Robots.txt

JS Todo App — создай полноценное приложение с LocalStorage и drag-and-drop.