HTML — Основа веб-страницы
HyperText Markup Language — язык разметки
HTML — это скелет любой веб-страницы. Он определяет структуру и семантику контента: заголовки, параграфы, списки, ссылки, изображения и другие элементы.
Семантический HTML означает использование тегов по их назначению.
Например, <header> для шапки, <nav> для навигации,
<article> для статьи. Это улучшает SEO и доступность.
Базовая структура HTML-документа
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="Описание страницы для SEO">
<title>Заголовок страницы</title>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<header>
<nav>
<a href="/">Главная</a>
<a href="/about">О нас</a>
</nav>
</header>
<main>
<article>
<h1>Заголовок статьи</h1>
<p>Текст статьи...</p>
</article>
</main>
<footer>
<p>© 2024 Компания</p>
</footer>
</body>
</html>
Основные семантические теги HTML5
| Тег | Назначение | Пример использования |
|---|---|---|
<header> |
Шапка страницы или секции | Логотип, навигация |
<nav> |
Навигационный блок | Меню, ссылки |
<main> |
Основной контент (один на страницу) | Содержимое страницы |
<article> |
Независимый контент | Статья, пост, карточка |
<section> |
Тематическая группировка | Раздел страницы |
<aside> |
Дополнительный контент | Сайдбар, реклама |
<footer> |
Подвал страницы или секции | Копирайт, ссылки |
<figure> |
Иллюстрация с подписью | Изображение + caption |
Пример карточки товара
<article class="product-card">
<figure class="product-card__image">
<img src="product.jpg" alt="iPhone 15 Pro" loading="lazy">
<figcaption class="visually-hidden">iPhone 15 Pro в цвете титан</figcaption>
</figure>
<div class="product-card__content">
<h3 class="product-card__title">iPhone 15 Pro</h3>
<p class="product-card__description">
Смартфон с чипом A17 Pro и титановым корпусом
</p>
<div class="product-card__price">
<span class="product-card__price-old">129 990 ₽</span>
<span class="product-card__price-new">119 990 ₽</span>
</div>
<button class="product-card__button" type="button">
В корзину
</button>
</div>
</article>
- Всегда указывайте
langатрибут в<html> - Используйте
altдля изображений - Добавляйте
loading="lazy"для отложенной загрузки - Один
<h1>на страницу - Соблюдайте иерархию заголовков (h1 → h2 → h3)
CSS — Стилизация страницы
Cascading Style Sheets — каскадные таблицы стилей
CSS отвечает за внешний вид страницы: цвета, шрифты, отступы, расположение элементов, анимации и адаптивность.
Способы подключения CSS
<!-- 1. Внешний файл (рекомендуется) -->
<link rel="stylesheet" href="styles.css">
<!-- 2. Внутренние стили -->
<style>
.button { background: blue; }
</style>
<!-- 3. Инлайн-стили (избегайте) -->
<div style="color: red;">Текст</div>
Селекторы CSS
/* Селектор элемента */
p { color: #333; }
/* Селектор класса */
.button { background: #3b82f6; }
/* Селектор ID (избегайте для стилей) */
#header { height: 80px; }
/* Селектор атрибута */
input[type="email"] { border-color: blue; }
/* Псевдоклассы */
.button:hover { background: #2563eb; }
.button:focus { outline: 2px solid #93c5fd; }
.button:active { transform: scale(0.98); }
/* Псевдоэлементы */
.quote::before { content: '"'; }
.quote::after { content: '"'; }
/* Комбинаторы */
.card .title { } /* Потомок */
.card > .title { } /* Прямой потомок */
.card + .card { } /* Соседний элемент */
.card ~ .card { } /* Все следующие */
/* Современные селекторы */
.item:nth-child(odd) { background: #f9fafb; }
.item:first-child { border-top: none; }
.item:last-child { border-bottom: none; }
.link:not(.disabled) { cursor: pointer; }
Flexbox — гибкая раскладка
/* Базовый flex-контейнер */
.container {
display: flex;
gap: 20px; /* Отступы между элементами */
}
/* Горизонтальное выравнивание */
.row {
display: flex;
justify-content: space-between; /* Распределение по горизонтали */
align-items: center; /* Выравнивание по вертикали */
}
/* Вертикальный flex */
.column {
display: flex;
flex-direction: column;
gap: 16px;
}
/* Центрирование */
.centered {
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
}
/* Flex-элементы */
.sidebar { flex: 0 0 280px; } /* Фиксированная ширина */
.content { flex: 1; } /* Занять всё оставшееся */
.aside { flex: 0 0 auto; } /* По размеру контента */
/* Перенос на новую строку */
.grid {
display: flex;
flex-wrap: wrap;
gap: 20px;
}
.grid__item {
flex: 0 0 calc(33.333% - 14px); /* 3 колонки с учётом gap */
}
CSS Grid — сетка
/* Базовая сетка */
.grid {
display: grid;
grid-template-columns: repeat(3, 1fr); /* 3 равных колонки */
gap: 24px;
}
/* Адаптивная сетка (auto-fit) */
.cards {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
gap: 20px;
}
/* Сложная раскладка */
.layout {
display: grid;
grid-template-columns: 280px 1fr 300px;
grid-template-rows: auto 1fr auto;
grid-template-areas:
"header header header"
"sidebar main aside"
"footer footer footer";
min-height: 100vh;
}
.header { grid-area: header; }
.sidebar { grid-area: sidebar; }
.main { grid-area: main; }
.aside { grid-area: aside; }
.footer { grid-area: footer; }
/* Позиционирование элементов */
.featured {
grid-column: span 2; /* Занять 2 колонки */
grid-row: span 2; /* Занять 2 ряда */
}
Адаптивность — Media Queries
/* Mobile First подход (рекомендуется) */
/* Базовые стили — для мобильных */
.container {
padding: 16px;
}
.grid {
display: grid;
grid-template-columns: 1fr;
gap: 16px;
}
/* Планшеты (768px и выше) */
@media (min-width: 768px) {
.container {
padding: 24px;
}
.grid {
grid-template-columns: repeat(2, 1fr);
gap: 20px;
}
}
/* Десктоп (1024px и выше) */
@media (min-width: 1024px) {
.container {
max-width: 1200px;
margin: 0 auto;
padding: 32px;
}
.grid {
grid-template-columns: repeat(3, 1fr);
gap: 24px;
}
}
/* Большие экраны */
@media (min-width: 1440px) {
.grid {
grid-template-columns: repeat(4, 1fr);
}
}
/* Современные медиа-запросы */
@media (hover: hover) {
/* Стили только для устройств с hover */
.button:hover { transform: translateY(-2px); }
}
@media (prefers-color-scheme: dark) {
/* Тёмная тема системы */
:root {
--bg: #1a1a2e;
--text: #e4e4e7;
}
}
@media (prefers-reduced-motion: reduce) {
/* Отключение анимаций для пользователей */
* { animation: none !important; }
}
CSS Custom Properties (переменные)
/* Определение переменных */
:root {
/* Цвета */
--color-primary: #667eea;
--color-primary-dark: #5a67d8;
--color-secondary: #764ba2;
--color-text: #1a1a2e;
--color-text-muted: #6b7280;
--color-background: #f5f7fa;
--color-white: #ffffff;
/* Типографика */
--font-family: 'Inter', sans-serif;
--font-size-sm: 0.875rem;
--font-size-base: 1rem;
--font-size-lg: 1.25rem;
--font-size-xl: 1.5rem;
/* Отступы */
--spacing-xs: 0.25rem;
--spacing-sm: 0.5rem;
--spacing-md: 1rem;
--spacing-lg: 1.5rem;
--spacing-xl: 2rem;
/* Скругления */
--radius-sm: 4px;
--radius-md: 8px;
--radius-lg: 16px;
--radius-full: 9999px;
/* Тени */
--shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.05);
--shadow-md: 0 4px 6px rgba(0, 0, 0, 0.1);
--shadow-lg: 0 10px 25px rgba(0, 0, 0, 0.15);
/* Анимации */
--transition-fast: 150ms ease;
--transition-base: 200ms ease;
--transition-slow: 300ms ease;
}
/* Использование переменных */
.button {
background: var(--color-primary);
color: var(--color-white);
padding: var(--spacing-sm) var(--spacing-md);
border-radius: var(--radius-md);
font-family: var(--font-family);
font-size: var(--font-size-base);
box-shadow: var(--shadow-sm);
transition: all var(--transition-base);
}
.button:hover {
background: var(--color-primary-dark);
box-shadow: var(--shadow-md);
}
/* Тёмная тема через переменные */
[data-theme="dark"] {
--color-text: #e4e4e7;
--color-background: #1a1a2e;
--color-white: #2d2d5a;
}
SCSS/Sass — CSS-препроцессор
Syntactically Awesome Style Sheets
SCSS — это надстройка над CSS, которая добавляет переменные, вложенность, миксины, функции и другие возможности. SCSS-код компилируется в обычный CSS.
Sass использует отступы вместо скобок (как Python).
SCSS использует обычный CSS-синтаксис со скобками.
SCSS более популярен, так как любой CSS-код — это валидный SCSS.
Переменные в SCSS
// Переменные
$primary-color: #667eea;
$secondary-color: #764ba2;
$text-color: #1a1a2e;
$font-family: 'Inter', sans-serif;
$border-radius: 8px;
$spacing-unit: 8px;
// Использование
.button {
background: $primary-color;
color: white;
font-family: $font-family;
border-radius: $border-radius;
padding: $spacing-unit * 2; // 16px
margin-bottom: $spacing-unit * 3; // 24px
}
// Мапы (объекты)
$colors: (
'primary': #667eea,
'secondary': #764ba2,
'success': #10b981,
'danger': #ef4444,
'warning': #f59e0b
);
// Получение значения из мапы
.alert-success {
background: map-get($colors, 'success');
}
// Или современный синтаксис
$breakpoints: (
'sm': 640px,
'md': 768px,
'lg': 1024px,
'xl': 1280px
);
Вложенность (Nesting)
// SCSS с вложенностью
.card {
background: white;
border-radius: 12px;
padding: 24px;
// Вложенный элемент
.card__header {
display: flex;
align-items: center;
margin-bottom: 16px;
}
.card__title {
font-size: 1.25rem;
font-weight: 600;
// Псевдоклассы через &
&:hover {
color: $primary-color;
}
}
.card__body {
color: $text-color;
}
// Модификаторы через &
&--featured {
border: 2px solid $primary-color;
background: linear-gradient(135deg, #f5f3ff, #ede9fe);
}
&--compact {
padding: 16px;
}
// Состояния
&:hover {
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.1);
}
&:focus-within {
outline: 2px solid $primary-color;
}
// Медиа-запросы внутри селектора
@media (max-width: 768px) {
padding: 16px;
.card__title {
font-size: 1.125rem;
}
}
}
// Компилируется в CSS:
// .card { ... }
// .card .card__header { ... }
// .card .card__title { ... }
// .card .card__title:hover { ... }
// .card--featured { ... }
// .card:hover { ... }
// @media (max-width: 768px) { .card { ... } }
Миксины (Mixins)
// Простой миксин
@mixin flex-center {
display: flex;
justify-content: center;
align-items: center;
}
// Миксин с параметрами
@mixin button-variant($bg-color, $text-color: white) {
background: $bg-color;
color: $text-color;
border: none;
padding: 12px 24px;
border-radius: 8px;
font-weight: 500;
cursor: pointer;
transition: all 0.2s;
&:hover {
background: darken($bg-color, 10%);
transform: translateY(-2px);
}
&:active {
transform: translateY(0);
}
&:disabled {
opacity: 0.5;
cursor: not-allowed;
transform: none;
}
}
// Миксин для медиа-запросов
@mixin respond-to($breakpoint) {
@if $breakpoint == 'sm' {
@media (min-width: 640px) { @content; }
} @else if $breakpoint == 'md' {
@media (min-width: 768px) { @content; }
} @else if $breakpoint == 'lg' {
@media (min-width: 1024px) { @content; }
} @else if $breakpoint == 'xl' {
@media (min-width: 1280px) { @content; }
}
}
// Использование миксинов
.hero {
@include flex-center;
min-height: 100vh;
}
.btn-primary {
@include button-variant($primary-color);
}
.btn-secondary {
@include button-variant($secondary-color);
}
.btn-outline {
@include button-variant(transparent, $primary-color);
border: 2px solid $primary-color;
}
.grid {
display: grid;
grid-template-columns: 1fr;
gap: 16px;
@include respond-to('md') {
grid-template-columns: repeat(2, 1fr);
gap: 20px;
}
@include respond-to('lg') {
grid-template-columns: repeat(3, 1fr);
gap: 24px;
}
}
Функции и операции
// Встроенные функции
$base-color: #667eea;
.element {
background: $base-color;
border-color: darken($base-color, 15%); // Темнее
color: lighten($base-color, 40%); // Светлее
box-shadow: 0 4px 20px rgba($base-color, 0.3); // Прозрачность
}
// Математические операции
$base-size: 16px;
$spacing: 8px;
.text-sm { font-size: $base-size * 0.875; } // 14px
.text-lg { font-size: $base-size * 1.25; } // 20px
.text-xl { font-size: $base-size * 1.5; } // 24px
.margin-1 { margin: $spacing * 1; } // 8px
.margin-2 { margin: $spacing * 2; } // 16px
.margin-3 { margin: $spacing * 3; } // 24px
// Пользовательские функции
@function rem($pixels) {
@return ($pixels / 16) * 1rem;
}
@function spacing($multiplier) {
@return $spacing * $multiplier;
}
// Использование
.card {
padding: rem(24); // 1.5rem
margin-bottom: spacing(3); // 24px
font-size: rem(18); // 1.125rem
}
// Условия
@function text-contrast($bg-color) {
@if (lightness($bg-color) > 50%) {
@return #1a1a2e; // Тёмный текст
} @else {
@return #ffffff; // Светлый текст
}
}
.badge {
background: $primary-color;
color: text-contrast($primary-color);
}
Модульная структура проекта
// Структура папок:
// styles/
// ├── main.scss # Главный файл
// ├── _variables.scss # Переменные
// ├── _mixins.scss # Миксины
// ├── _base.scss # Reset, базовые стили
// ├── _typography.scss # Типографика
// ├── components/
// │ ├── _button.scss
// │ ├── _card.scss
// │ └── _modal.scss
// └── pages/
// ├── _home.scss
// └── _about.scss
// main.scss
@use 'variables' as *;
@use 'mixins' as *;
@use 'base';
@use 'typography';
@use 'components/button';
@use 'components/card';
@use 'components/modal';
@use 'pages/home';
@use 'pages/about';
// _variables.scss
$primary-color: #667eea !default;
$secondary-color: #764ba2 !default;
// _mixins.scss
@mixin flex-center { ... }
@mixin respond-to($bp) { ... }
// components/_button.scss
.button {
@include button-variant($primary-color);
&--secondary {
@include button-variant($secondary-color);
}
}
- Не вкладывайте больше 3-4 уровней
- Используйте
@useвместо@import - Группируйте переменные в мапы
- Создавайте миксины для повторяющегося кода
- Называйте файлы с
_(partials)
BEM — Методология именования
Block Element Modifier
BEM — это соглашение об именовании CSS-классов, которое делает код предсказуемым, переиспользуемым и легко поддерживаемым. Разработана в Яндексе.
Структура BEM
Block (Блок) — самостоятельный компонент: card, menu, button
Element (Элемент) — часть блока: card__title, menu__item
Modifier (Модификатор) — вариация: button--primary, card--featured
Примеры BEM
<!-- Блок: card -->
<article class="card">
<!-- Элемент: card__image -->
<div class="card__image">
<img src="photo.jpg" alt="Фото">
</div>
<!-- Элемент: card__content -->
<div class="card__content">
<!-- Элемент: card__title -->
<h3 class="card__title">Заголовок карточки</h3>
<!-- Элемент: card__text -->
<p class="card__text">Описание карточки...</p>
<!-- Элемент + вложенный блок button -->
<button class="card__button button button--primary">
Подробнее
</button>
</div>
</article>
<!-- Модификатор блока: card--featured -->
<article class="card card--featured">
<div class="card__image">...</div>
<div class="card__content">...</div>
</article>
<!-- Модификатор элемента: card__title--large -->
<h3 class="card__title card__title--large">Большой заголовок</h3>
// Блок
.card {
background: white;
border-radius: 12px;
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1);
overflow: hidden;
// Элементы (через &)
&__image {
width: 100%;
height: 200px;
overflow: hidden;
img {
width: 100%;
height: 100%;
object-fit: cover;
}
}
&__content {
padding: 24px;
}
&__title {
font-size: 1.25rem;
font-weight: 600;
margin-bottom: 8px;
color: #1a1a2e;
// Модификатор элемента
&--large {
font-size: 1.5rem;
}
&--muted {
color: #6b7280;
}
}
&__text {
color: #6b7280;
line-height: 1.6;
margin-bottom: 16px;
}
&__button {
width: 100%;
}
// Модификаторы блока
&--featured {
border: 2px solid #667eea;
background: linear-gradient(135deg, #f5f3ff, #ede9fe);
.card__title {
color: #667eea;
}
}
&--horizontal {
display: flex;
.card__image {
width: 200px;
height: auto;
flex-shrink: 0;
}
}
&--compact {
.card__content {
padding: 16px;
}
.card__title {
font-size: 1rem;
}
}
// Состояния (не BEM, но часто используются вместе)
&.is-loading {
opacity: 0.7;
pointer-events: none;
}
&.is-selected {
box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.4);
}
}
// Отдельный блок: button
.button {
display: inline-flex;
align-items: center;
justify-content: center;
gap: 8px;
padding: 12px 24px;
border: none;
border-radius: 8px;
font-weight: 500;
cursor: pointer;
transition: all 0.2s;
&__icon {
width: 20px;
height: 20px;
}
&__text {
// Текст кнопки
}
// Модификаторы размера
&--small {
padding: 8px 16px;
font-size: 0.875rem;
}
&--large {
padding: 16px 32px;
font-size: 1.125rem;
}
// Модификаторы цвета
&--primary {
background: #667eea;
color: white;
&:hover {
background: #5a67d8;
}
}
&--secondary {
background: #764ba2;
color: white;
&:hover {
background: #6b4190;
}
}
&--outline {
background: transparent;
color: #667eea;
border: 2px solid #667eea;
&:hover {
background: #667eea;
color: white;
}
}
&--ghost {
background: transparent;
color: #667eea;
&:hover {
background: rgba(102, 126, 234, 0.1);
}
}
// Модификатор ширины
&--full-width {
width: 100%;
}
// Состояние disabled
&:disabled,
&--disabled {
opacity: 0.5;
cursor: not-allowed;
pointer-events: none;
}
}
Визуальный пример BEM
Обычная карточка
Это базовый блок .card без модификаторов
Featured карточка
Блок с модификатором .card--featured
Правила BEM
| Правило | ✅ Правильно | ❌ Неправильно |
|---|---|---|
| Элемент принадлежит блоку | .card__title |
.card__content__title |
| Нет вложенных элементов | .menu__link |
.menu__item__link |
| Модификатор дополняет | class="btn btn--large" |
class="btn--large" |
| Блоки независимы | .header .logo |
.header__logo (если logo — отдельный блок) |
| Именование | .product-card__image |
.productCardImage |
Реальный пример: форма авторизации
<form class="auth-form">
<div class="auth-form__header">
<h2 class="auth-form__title">Вход в аккаунт</h2>
<p class="auth-form__subtitle">Введите ваши данные</p>
</div>
<div class="auth-form__body">
<!-- Отдельный блок: input-field -->
<div class="input-field">
<label class="input-field__label">Email</label>
<input
type="email"
class="input-field__input"
placeholder="email@example.com"
>
<span class="input-field__error">Введите корректный email</span>
</div>
<div class="input-field">
<label class="input-field__label">Пароль</label>
<input
type="password"
class="input-field__input input-field__input--with-icon"
>
<button type="button" class="input-field__icon">
👁️
</button>
</div>
<div class="input-field input-field--checkbox">
<input type="checkbox" class="input-field__checkbox" id="remember">
<label class="input-field__label" for="remember">Запомнить меня</label>
</div>
</div>
<div class="auth-form__footer">
<button type="submit" class="button button--primary button--full-width">
Войти
</button>
<div class="auth-form__divider">
<span>или</span>
</div>
<button type="button" class="button button--outline button--full-width">
<span class="button__icon">🔵</span>
<span class="button__text">Войти через Google</span>
</button>
</div>
<p class="auth-form__link">
Нет аккаунта? <a href="/register">Зарегистрироваться</a>
</p>
</form>
.auth-form {
max-width: 400px;
margin: 0 auto;
padding: 32px;
background: white;
border-radius: 16px;
box-shadow: 0 10px 40px rgba(0, 0, 0, 0.1);
&__header {
text-align: center;
margin-bottom: 32px;
}
&__title {
font-size: 1.5rem;
font-weight: 700;
margin-bottom: 8px;
}
&__subtitle {
color: #6b7280;
}
&__body {
display: flex;
flex-direction: column;
gap: 20px;
margin-bottom: 24px;
}
&__footer {
display: flex;
flex-direction: column;
gap: 16px;
}
&__divider {
display: flex;
align-items: center;
gap: 16px;
color: #9ca3af;
font-size: 0.875rem;
&::before,
&::after {
content: '';
flex: 1;
height: 1px;
background: #e5e7eb;
}
}
&__link {
text-align: center;
margin-top: 24px;
color: #6b7280;
font-size: 0.875rem;
a {
color: #667eea;
font-weight: 500;
}
}
}
// Блок input-field
.input-field {
display: flex;
flex-direction: column;
gap: 6px;
position: relative;
&__label {
font-size: 0.875rem;
font-weight: 500;
color: #374151;
}
&__input {
padding: 12px 16px;
border: 1px solid #d1d5db;
border-radius: 8px;
font-size: 1rem;
transition: all 0.2s;
&:focus {
outline: none;
border-color: #667eea;
box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.2);
}
&--with-icon {
padding-right: 48px;
}
&--error {
border-color: #ef4444;
&:focus {
box-shadow: 0 0 0 3px rgba(239, 68, 68, 0.2);
}
}
}
&__icon {
position: absolute;
right: 12px;
top: 50%;
transform: translateY(-50%);
background: none;
border: none;
cursor: pointer;
padding: 4px;
}
&__error {
font-size: 0.75rem;
color: #ef4444;
display: none;
}
&--checkbox {
flex-direction: row;
align-items: center;
gap: 8px;
}
&--has-error {
.input-field__error {
display: block;
}
}
}
- Понятная связь HTML и CSS
- Нет конфликтов имён (специфичность всегда одинаковая)
- Легко переиспользовать компоненты
- Простой рефакторинг
- Хорошо работает в команде
Tailwind CSS — Utility-First
Фреймворк утилитарных классов
Tailwind CSS — это CSS-фреймворк, где стили применяются через маленькие утилитарные классы прямо в HTML. Вместо написания CSS вы комбинируете готовые классы.
Вместо .card { padding: 16px; background: white; } вы пишете
<div class="p-4 bg-white">. Каждый класс делает одну вещь.
Установка Tailwind
# Создание проекта
npm init -y
# Установка Tailwind
npm install -D tailwindcss postcss autoprefixer
# Инициализация конфигурации
npx tailwindcss init -p
# Структура файлов:
# ├── src/
# │ └── input.css
# ├── dist/
# │ └── output.css
# ├── tailwind.config.js
# └── postcss.config.js
/** @type {import('tailwindcss').Config} */
module.exports = {
content: [
"./src/**/*.{html,js,jsx,ts,tsx}",
"./public/index.html"
],
theme: {
extend: {
colors: {
primary: {
50: '#f5f3ff',
100: '#ede9fe',
500: '#667eea',
600: '#5a67d8',
700: '#4c51bf',
},
secondary: '#764ba2',
},
fontFamily: {
sans: ['Inter', 'sans-serif'],
},
spacing: {
'18': '4.5rem',
'88': '22rem',
},
borderRadius: {
'4xl': '2rem',
},
},
},
plugins: [
require('@tailwindcss/forms'),
require('@tailwindcss/typography'),
],
}
@tailwind base;
@tailwind components;
@tailwind utilities;
/* Кастомные компоненты */
@layer components {
.btn {
@apply px-4 py-2 rounded-lg font-medium transition-all duration-200;
}
.btn-primary {
@apply bg-primary-500 text-white hover:bg-primary-600;
}
.card {
@apply bg-white rounded-xl shadow-lg p-6;
}
}
/* Кастомные утилиты */
@layer utilities {
.text-gradient {
@apply bg-clip-text text-transparent bg-gradient-to-r from-primary-500 to-secondary;
}
}
Основные классы Tailwind
Отступы и размеры
<!-- Padding (внутренние отступы) -->
<div class="p-4">...</div> <!-- padding: 1rem (16px) -->
<div class="px-4">...</div> <!-- padding-left/right: 1rem -->
<div class="py-2">...</div> <!-- padding-top/bottom: 0.5rem -->
<div class="pt-8">...</div> <!-- padding-top: 2rem -->
<div class="pl-6">...</div> <!-- padding-left: 1.5rem -->
<!-- Margin (внешние отступы) -->
<div class="m-4">...</div> <!-- margin: 1rem -->
<div class="mx-auto">...</div> <!-- margin-left/right: auto -->
<div class="mt-8">...</div> <!-- margin-top: 2rem -->
<div class="-mt-4">...</div> <!-- margin-top: -1rem -->
<div class="mb-0">...</div> <!-- margin-bottom: 0 -->
<!-- Gap (для flex/grid) -->
<div class="gap-4">...</div> <!-- gap: 1rem -->
<div class="gap-x-2">...</div> <!-- column-gap: 0.5rem -->
<div class="gap-y-6">...</div> <!-- row-gap: 1.5rem -->
<!-- Space between children -->
<div class="space-y-4"> <!-- margin-top между детьми -->
<div>Item 1</div>
<div>Item 2</div>
<div>Item 3</div>
</div>
<!-- Шкала: 0, 0.5, 1, 1.5, 2, 2.5, 3, 3.5, 4, 5, 6, 7, 8, 9, 10, 11, 12, 14, 16, 20, 24... -->
<!-- 1 = 0.25rem = 4px -->
Flexbox и Grid
<!-- Flex контейнер -->
<div class="flex">...</div>
<div class="inline-flex">...</div>
<!-- Направление -->
<div class="flex flex-row">...</div> <!-- По умолчанию -->
<div class="flex flex-col">...</div> <!-- Вертикально -->
<div class="flex flex-row-reverse">...</div>
<!-- Выравнивание -->
<div class="flex justify-start">...</div>
<div class="flex justify-center">...</div>
<div class="flex justify-end">...</div>
<div class="flex justify-between">...</div>
<div class="flex justify-around">...</div>
<div class="flex items-start">...</div>
<div class="flex items-center">...</div>
<div class="flex items-end">...</div>
<div class="flex items-stretch">...</div>
<!-- Перенос -->
<div class="flex flex-wrap">...</div>
<div class="flex flex-nowrap">...</div>
<!-- Центрирование -->
<div class="flex items-center justify-center min-h-screen">
Идеально по центру
</div>
<!-- Flex-элементы -->
<div class="flex-1">...</div> <!-- flex: 1 1 0% -->
<div class="flex-auto">...</div> <!-- flex: 1 1 auto -->
<div class="flex-none">...</div> <!-- flex: none -->
<div class="flex-shrink-0">...</div> <!-- не сжимается -->
<div class="flex-grow">...</div> <!-- растягивается -->
<!-- Grid контейнер -->
<div class="grid">...</div>
<!-- Колонки -->
<div class="grid grid-cols-1">...</div>
<div class="grid grid-cols-2">...</div>
<div class="grid grid-cols-3">...</div>
<div class="grid grid-cols-4">...</div>
<div class="grid grid-cols-12">...</div>
<!-- Адаптивная сетка -->
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-6">
<div>Card 1</div>
<div>Card 2</div>
<div>Card 3</div>
<div>Card 4</div>
</div>
<!-- Span (занять несколько колонок) -->
<div class="col-span-2">...</div>
<div class="col-span-full">...</div>
<div class="col-start-2 col-end-4">...</div>
<!-- Ряды -->
<div class="grid grid-rows-3">...</div>
<div class="row-span-2">...</div>
<!-- Auto columns/rows -->
<div class="grid auto-cols-fr">...</div>
<div class="grid auto-rows-min">...</div>
Цвета и фоны
<!-- Цвет текста -->
<p class="text-black">...</p>
<p class="text-white">...</p>
<p class="text-gray-500">...</p>
<p class="text-blue-600">...</p>
<p class="text-red-500">...</p>
<p class="text-emerald-400">...</p>
<!-- Цвет фона -->
<div class="bg-white">...</div>
<div class="bg-gray-100">...</div>
<div class="bg-blue-500">...</div>
<div class="bg-gradient-to-r from-purple-500 to-pink-500">...</div>
<!-- Прозрачность -->
<div class="bg-black/50">...</div> <!-- 50% прозрачность -->
<div class="bg-white/80">...</div> <!-- 80% прозрачность -->
<p class="text-gray-900/75">...</p>
<!-- Рамки -->
<div class="border border-gray-200">...</div>
<div class="border-2 border-blue-500">...</div>
<div class="border-b border-gray-300">...</div>
<!-- Градиенты -->
<div class="bg-gradient-to-r from-cyan-500 to-blue-500">...</div>
<div class="bg-gradient-to-br from-pink-500 via-red-500 to-yellow-500">...</div>
Типографика
<!-- Размер шрифта -->
<p class="text-xs">12px</p>
<p class="text-sm">14px</p>
<p class="text-base">16px</p>
<p class="text-lg">18px</p>
<p class="text-xl">20px</p>
<p class="text-2xl">24px</p>
<p class="text-4xl">36px</p>
<p class="text-6xl">60px</p>
<!-- Начертание -->
<p class="font-light">300</p>
<p class="font-normal">400</p>
<p class="font-medium">500</p>
<p class="font-semibold">600</p>
<p class="font-bold">700</p>
<!-- Выравнивание -->
<p class="text-left">...</p>
<p class="text-center">...</p>
<p class="text-right">...</p>
<p class="text-justify">...</p>
<!-- Высота строки -->
<p class="leading-none">1</p>
<p class="leading-tight">1.25</p>
<p class="leading-normal">1.5</p>
<p class="leading-relaxed">1.625</p>
<p class="leading-loose">2</p>
<!-- Трансформация -->
<p class="uppercase">ВЕРХНИЙ РЕГИСТР</p>
<p class="lowercase">нижний регистр</p>
<p class="capitalize">Каждое Слово</p>
<!-- Декорация -->
<p class="underline">подчёркнутый</p>
<p class="line-through">зачёркнутый</p>
<!-- Обрезка текста -->
<p class="truncate">Очень длинный текст...</p>
<p class="line-clamp-2">Ограничить 2 строками...</p>
Адаптивность
<!--
Breakpoints в Tailwind:
sm: 640px и выше
md: 768px и выше
lg: 1024px и выше
xl: 1280px и выше
2xl: 1536px и выше
-->
<!-- Mobile-first подход -->
<div class="
w-full
sm:w-1/2
lg:w-1/3
xl:w-1/4
">
Адаптивная ширина
</div>
<!-- Скрытие/показ -->
<div class="hidden md:block">
Видно только на md и выше
</div>
<div class="block md:hidden">
Видно только на мобильных
</div>
<!-- Адаптивная сетка -->
<div class="
grid
grid-cols-1
sm:grid-cols-2
lg:grid-cols-3
xl:grid-cols-4
gap-4
sm:gap-6
lg:gap-8
">
<div>Item 1</div>
<div>Item 2</div>
<div>Item 3</div>
<div>Item 4</div>
</div>
<!-- Адаптивные отступы -->
<div class="p-4 sm:p-6 lg:p-8 xl:p-12">
Отступы растут с размером экрана
</div>
<!-- Адаптивный текст -->
<h1 class="text-2xl sm:text-3xl lg:text-4xl xl:text-5xl font-bold">
Адаптивный заголовок
</h1>
Состояния и интерактивность
<!-- Hover -->
<button class="
bg-blue-500
hover:bg-blue-600
hover:scale-105
hover:shadow-lg
">
Наведи на меня
</button>
<!-- Focus -->
<input class="
border border-gray-300
focus:border-blue-500
focus:ring-2
focus:ring-blue-200
focus:outline-none
">
<!-- Active -->
<button class="
bg-blue-500
active:bg-blue-700
active:scale-95
">
Нажми меня
</button>
<!-- Group hover (hover на родителе) -->
<div class="group p-4 hover:bg-gray-100 rounded-lg cursor-pointer">
<h3 class="group-hover:text-blue-500">Заголовок</h3>
<p class="group-hover:text-gray-600">Текст меняется при hover на карточку</p>
<span class="opacity-0 group-hover:opacity-100 transition-opacity">
→
</span>
</div>
<!-- Peer (состояние соседа) -->
<input type="checkbox" class="peer" id="toggle">
<label for="toggle" class="peer-checked:bg-blue-500">
Цвет меняется когда чекбокс активен
</label>
<!-- First, Last, Odd, Even -->
<ul>
<li class="first:pt-0 last:pb-0 odd:bg-gray-50 even:bg-white">Item</li>
</ul>
<!-- Dark mode -->
<div class="bg-white dark:bg-gray-900 text-black dark:text-white">
Поддержка тёмной темы
</div>
<!-- Disabled -->
<button class="bg-blue-500 disabled:opacity-50 disabled:cursor-not-allowed" disabled>
Неактивная кнопка
</button>
Полный пример: карточка на Tailwind
<article class="
group
bg-white
rounded-2xl
shadow-md
hover:shadow-xl
overflow-hidden
transition-all
duration-300
max-w-sm
">
<!-- Изображение -->
<div class="relative overflow-hidden">
<img
src="product.jpg"
alt="iPhone 15 Pro"
class="
w-full
h-64
object-cover
group-hover:scale-110
transition-transform
duration-500
"
>
<!-- Бейдж -->
<span class="
absolute
top-4
left-4
bg-red-500
text-white
text-xs
font-bold
px-3
py-1
rounded-full
">
-15%
</span>
<!-- Кнопка избранного -->
<button class="
absolute
top-4
right-4
w-10
h-10
bg-white/80
backdrop-blur-sm
rounded-full
flex
items-center
justify-center
opacity-0
group-hover:opacity-100
transition-opacity
hover:bg-white
hover:text-red-500
">
❤️
</button>
</div>
<!-- Контент -->
<div class="p-6">
<!-- Категория -->
<span class="text-xs text-gray-500 uppercase tracking-wider">
Смартфоны
</span>
<!-- Заголовок -->
<h3 class="
mt-2
text-lg
font-semibold
text-gray-900
group-hover:text-blue-600
transition-colors
">
iPhone 15 Pro
</h3>
<!-- Описание -->
<p class="mt-2 text-gray-600 text-sm line-clamp-2">
Смартфон с чипом A17 Pro и титановым корпусом.
Революционная камера и невероятная производительность.
</p>
<!-- Рейтинг -->
<div class="flex items-center gap-1 mt-3">
<span class="text-yellow-400">★★★★★</span>
<span class="text-sm text-gray-500">(128 отзывов)</span>
</div>
<!-- Цена и кнопка -->
<div class="flex items-center justify-between mt-4 pt-4 border-t border-gray-100">
<div>
<span class="text-sm text-gray-400 line-through">129 990 ₽</span>
<span class="block text-xl font-bold text-gray-900">119 990 ₽</span>
</div>
<button class="
px-6
py-3
bg-blue-600
hover:bg-blue-700
active:bg-blue-800
text-white
font-medium
rounded-xl
transition-colors
flex
items-center
gap-2
">
<span>🛒</span>
В корзину
</button>
</div>
</div>
</article>
- Быстрая разработка — не нужно писать CSS
- Консистентность — используется дизайн-система
- Маленький итоговый CSS — PurgeCSS удаляет неиспользуемое
- Отлично работает с компонентными фреймворками (React, Vue)
- Легко кастомизировать через конфиг
- Длинные классы в HTML — может быть «грязно»
- Нужно учить названия классов
- Сложнее для уникальных дизайнов (выход за рамки системы)
- Зависимость от инструментов сборки
Сравнение подходов
Что выбрать для проекта?
Сравнительная таблица
| Критерий | Чистый CSS | SCSS + BEM | Tailwind |
|---|---|---|---|
| Скорость разработки | Медленно | Средне | Быстро |
| Порог входа | Низкий | Средний | Средний |
| Масштабируемость | Сложно | Отлично | Хорошо |
| Размер CSS | Зависит | Может расти | Минимальный (с PurgeCSS) |
| Кастомизация | Полная | Полная | Через конфиг |
| Чистота HTML | Чистый | Чистый | Много классов |
| Командная работа | Сложно | Отлично | Хорошо |
| Переиспользование | Сложно | Отлично | Через компоненты |
Когда что использовать?
- Маленькие проекты, лендинги
- Изучение основ
- Когда не нужна сборка
- Средние и большие проекты
- Командная разработка
- Уникальный дизайн
- Долгосрочная поддержка
- Быстрое прототипирование
- React/Vue/Svelte проекты
- Когда есть дизайн-система
- MVP и стартапы
Комбинированный подход
На практике часто комбинируют подходы. Например, используют Tailwind для быстрой разработки и создают компоненты в SCSS для сложных элементов:
/* input.css */
@tailwind base;
@tailwind components;
@tailwind utilities;
/* Кастомный компонент со сложной анимацией */
@layer components {
.animated-button {
@apply px-6 py-3 rounded-lg font-medium;
position: relative;
overflow: hidden;
&::before {
content: '';
position: absolute;
top: 50%;
left: 50%;
width: 0;
height: 0;
background: rgba(255, 255, 255, 0.2);
border-radius: 50%;
transform: translate(-50%, -50%);
transition: width 0.6s, height 0.6s;
}
&:hover::before {
width: 300px;
height: 300px;
}
}
}
Итоговые рекомендации
- Начинающий разработчик? → Изучите сначала чистый CSS, потом SCSS
- Работаете в команде? → SCSS + BEM для единообразия
- Используете React/Vue? → Tailwind отлично интегрируется
- Уникальный сложный дизайн? → SCSS даёт больше контроля
- Быстрый прототип/MVP? → Tailwind ускорит разработку
- Долгосрочный проект? → SCSS + BEM легче поддерживать