Полное руководство по веб-вёрстке

От основ HTML до продвинутых методологий: всё, что нужно знать современному верстальщику

HTML5 CSS3 SCSS/Sass BEM Tailwind CSS
🏗️

HTML — Основа веб-страницы

HyperText Markup Language — язык разметки

HTML — это скелет любой веб-страницы. Он определяет структуру и семантику контента: заголовки, параграфы, списки, ссылки, изображения и другие элементы.

💡 Что такое семантика?

Семантический HTML означает использование тегов по их назначению. Например, <header> для шапки, <nav> для навигации, <article> для статьи. Это улучшает SEO и доступность.

Базовая структура HTML-документа

📄 Структура HTML5 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>&copy; 2024 Компания</p>
</footer>
</body>
</html>

Основные семантические теги HTML5

Тег Назначение Пример использования
<header> Шапка страницы или секции Логотип, навигация
<nav> Навигационный блок Меню, ссылки
<main> Основной контент (один на страницу) Содержимое страницы
<article> Независимый контент Статья, пост, карточка
<section> Тематическая группировка Раздел страницы
<aside> Дополнительный контент Сайдбар, реклама
<footer> Подвал страницы или секции Копирайт, ссылки
<figure> Иллюстрация с подписью Изображение + caption

Пример карточки товара

🛒 Семантичная карточка товара HTML
<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>
✅ Лучшие практики HTML
  • Всегда указывайте lang атрибут в <html>
  • Используйте alt для изображений
  • Добавляйте loading="lazy" для отложенной загрузки
  • Один <h1> на страницу
  • Соблюдайте иерархию заголовков (h1 → h2 → h3)
🎨

CSS — Стилизация страницы

Cascading Style Sheets — каскадные таблицы стилей

CSS отвечает за внешний вид страницы: цвета, шрифты, отступы, расположение элементов, анимации и адаптивность.

Способы подключения CSS

📎 Три способа подключения HTML/CSS
<!-- 1. Внешний файл (рекомендуется) -->
<link rel="stylesheet" href="styles.css">

<!-- 2. Внутренние стили -->
<style>
.button { background: blue; }
</style>

<!-- 3. Инлайн-стили (избегайте) -->
<div style="color: red;">Текст</div>

Селекторы CSS

🎯 Типы селекторов 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 — гибкая раскладка

📦 Flexbox примеры CSS
/* Базовый 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 — сетка

🔲 CSS Grid примеры CSS
/* Базовая сетка */
.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

📱 Адаптивные стили CSS
/* 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 (переменные)

🎛️ CSS-переменные CSS
/* Определение переменных */
: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 vs SCSS

Sass использует отступы вместо скобок (как Python).
SCSS использует обычный CSS-синтаксис со скобками.
SCSS более популярен, так как любой CSS-код — это валидный SCSS.

Переменные в 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
// 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)

🔧 Переиспользуемые блоки кода SCSS
// Простой миксин
@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;
}
}

Функции и операции

⚡ Функции SCSS SCSS
// Встроенные функции
$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);
}

Модульная структура проекта

📁 Организация файлов SCSS
// Структура папок:
// 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);
}
}
✅ Лучшие практики SCSS
  • Не вкладывайте больше 3-4 уровней
  • Используйте @use вместо @import
  • Группируйте переменные в мапы
  • Создавайте миксины для повторяющегося кода
  • Называйте файлы с _ (partials)
📐

BEM — Методология именования

Block Element Modifier

BEM — это соглашение об именовании CSS-классов, которое делает код предсказуемым, переиспользуемым и легко поддерживаемым. Разработана в Яндексе.

Структура BEM

🧱 Block__Element--Modifier

Block (Блок) — самостоятельный компонент: card, menu, button

Element (Элемент) — часть блока: card__title, menu__item

Modifier (Модификатор) — вариация: button--primary, card--featured

Примеры BEM

📋 HTML с BEM-классами HTML
<!-- Блок: 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>
🎨 CSS/SCSS для BEM SCSS
// Блок
.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

Результат BEM-разметки

Обычная карточка

Это базовый блок .card без модификаторов

Правила 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

Реальный пример: форма авторизации

📝 Форма в BEM HTML
<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>
🎨 SCSS для формы SCSS
.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;
    }
  }
}
✅ Преимущества BEM
  • Понятная связь HTML и CSS
  • Нет конфликтов имён (специфичность всегда одинаковая)
  • Легко переиспользовать компоненты
  • Простой рефакторинг
  • Хорошо работает в команде
🌊

Tailwind CSS — Utility-First

Фреймворк утилитарных классов

Tailwind CSS — это CSS-фреймворк, где стили применяются через маленькие утилитарные классы прямо в HTML. Вместо написания CSS вы комбинируете готовые классы.

💡 Utility-First подход

Вместо .card { padding: 16px; background: white; } вы пишете <div class="p-4 bg-white">. Каждый класс делает одну вещь.

Установка Tailwind

📦 Установка через npm Bash
# Создание проекта
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
⚙️ tailwind.config.js JavaScript
/** @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'),
  ],
}
📄 src/input.css CSS
@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

Отступы и размеры

📏 Spacing (отступы) HTML
<!-- 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

📦 Flexbox HTML
<!-- 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>     <!-- растягивается -->
🔲 CSS Grid HTML
<!-- 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>

Цвета и фоны

🎨 Цвета HTML
<!-- Цвет текста -->
<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>

Типографика

📝 Текст HTML
<!-- Размер шрифта -->
<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 HTML
<!-- 
  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, Focus, Active HTML
<!-- 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

🎴 Карточка товара HTML
<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>
✅ Преимущества Tailwind
  • Быстрая разработка — не нужно писать CSS
  • Консистентность — используется дизайн-система
  • Маленький итоговый CSS — PurgeCSS удаляет неиспользуемое
  • Отлично работает с компонентными фреймворками (React, Vue)
  • Легко кастомизировать через конфиг
⚠️ Недостатки Tailwind
  • Длинные классы в HTML — может быть «грязно»
  • Нужно учить названия классов
  • Сложнее для уникальных дизайнов (выход за рамки системы)
  • Зависимость от инструментов сборки
⚖️

Сравнение подходов

Что выбрать для проекта?

Сравнительная таблица

Критерий Чистый CSS SCSS + BEM Tailwind
Скорость разработки Медленно Средне Быстро
Порог входа Низкий Средний Средний
Масштабируемость Сложно Отлично Хорошо
Размер CSS Зависит Может расти Минимальный (с PurgeCSS)
Кастомизация Полная Полная Через конфиг
Чистота HTML Чистый Чистый Много классов
Командная работа Сложно Отлично Хорошо
Переиспользование Сложно Отлично Через компоненты

Когда что использовать?

🎯 Чистый CSS
  • Маленькие проекты, лендинги
  • Изучение основ
  • Когда не нужна сборка
🎯 SCSS + BEM
  • Средние и большие проекты
  • Командная разработка
  • Уникальный дизайн
  • Долгосрочная поддержка
🎯 Tailwind CSS
  • Быстрое прототипирование
  • React/Vue/Svelte проекты
  • Когда есть дизайн-система
  • MVP и стартапы

Комбинированный подход

На практике часто комбинируют подходы. Например, используют Tailwind для быстрой разработки и создают компоненты в SCSS для сложных элементов:

🔀 Комбинирование Tailwind и SCSS CSS
/* 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;
    }
  }
}

Итоговые рекомендации

📋 Чек-лист выбора технологии
  1. Начинающий разработчик? → Изучите сначала чистый CSS, потом SCSS
  2. Работаете в команде? → SCSS + BEM для единообразия
  3. Используете React/Vue? → Tailwind отлично интегрируется
  4. Уникальный сложный дизайн? → SCSS даёт больше контроля
  5. Быстрый прототип/MVP? → Tailwind ускорит разработку
  6. Долгосрочный проект? → SCSS + BEM легче поддерживать