CSS — стилизация веб-страниц

CSS (Cascading Style Sheets — каскадные таблицы стилей) отвечает за внешний вид страницы: цвета, шрифты, отступы, сетки и анимации. На этой странице ты научишься стилизовать карточки, кнопки и шапку сайта с нуля.

Уровень: начальный 28 разделов 4–5 часов

1. Что такое CSS и как его подключить

HTML определяет структуру страницы, CSS — её вид. Существует три способа подключить стили.

Внешний файл

Самый правильный способ — отдельный файл style.css, подключаемый в <head>:

<!-- в файле index.html -->
<head>
  <link rel="stylesheet" href="css/style.css">
</head>

Тег style

Стили можно встроить прямо в страницу. Подходит для коротких учебных примеров:

<style>
  h1 { color: #2563eb; }
</style>

Inline-стили

Атрибут style применяется к одному элементу. Используется редко — такой код сложно поддерживать:

<p style="color: red;">Красный текст</p>

Каскад и приоритеты

Слово «каскад» означает порядок применения правил. При конфликте побеждает правило с большим приоритетом:

  1. Inline-стили — самый высокий приоритет.
  2. Селектор с id.
  3. Селектор с классом.
  4. Селектор по тегу.
  5. Правило, объявленное позже в файле, перекрывает более раннее при равной специфичности.
Поэтому лучше всегда подключать внешний файл: стили в нём легко находить, переиспользовать и переопределять.

2. Селекторы

Селектор — это правило, указывающее, к каким элементам применить стиль. Базовые виды селекторов:

СелекторПримерЧто выбирает
тегp { ... }все абзацы
класс.btn { ... }элементы с class="btn"
id#logo { ... }элемент с id="logo"
атрибутinput[type="text"]инпуты нужного типа
вложенный.card p { ... }p внутри .card
потомок.card > p { ... }прямой потомок p
псевдоклассa:hover { ... }наведение мыши
p { color: #1f2937; }                    /* все абзацы */
.btn { padding: 10px 20px; }             /* по классу */
#logo { width: 40px; }                   /* по id */
input[type="email"] { border: 1px solid; }  /* по атрибуту */

.nav a:hover { color: #2563eb; }         /* :hover */
li:first-child { font-weight: 700; }     /* первый пункт */
.card > .card-title { margin: 0; }      /* прямой потомок */

Специфичность

Если два правила конфликтуют, побеждает то, у которого выше специфичность:

СелекторОчки специфичности
тег1
класс, атрибут, :hover10
id100
style="..." inline1000

Комбинации складываются: .card .title даёт 20 очков и перекроет одиночный .title.

3. Цвета и текст

В CSS цвет можно задать несколькими способами:

p {
  color: #2563eb;                  /* hex */
  color: rgb(37, 99, 235);         /* rgb */
  color: rgba(37, 99, 235, 0.7);   /* rgb + прозрачность */
  color: hsl(221, 83%, 53%);       /* hsl */
  color: red;                      /* ключевые слова */
}

Настройка текста

body {
  font-family: "Segoe UI", Arial, sans-serif;
  font-size: 16px;
  font-weight: 400;               /* от 100 до 900 */
  line-height: 1.6;               /* межстрочный интервал */
  text-align: left;
}

h1 {
  font-size: 2rem;
  font-weight: 700;
  text-align: center;
}
Единица rem считается от базового размера шрифта страницы (обычно 16px), поэтому 2rem = 32px. Гораздо удобнее пикселей при адаптивной вёрстке.

4. Box model

Каждый элемент — это прямоугольный блок, состоящий из четырёх слоёв:

.card {
  width: 300px;
  padding: 20px;       /* внутренний отступ до контента */
  border: 1px solid #e5e7eb;
  margin: 16px auto;   /* внешний отступ, центрирование */
}
СвойствоЧто задаёт
width / heightразмеры блока
paddingпространство между контентом и границей
borderграница элемента
marginотступ от соседних блоков
box-sizingкак считается итоговый размер
По умолчанию width считается без padding и border, из-за чего блок получается шире, чем ожидалось. Всегда подключай box-sizing: border-box — тогда указанная ширина включает padding и border.
* {
  box-sizing: border-box;
}

/* теперь .card шириной 300px останется 300px, 
   как бы ни менялись padding и border */

5. Фон и границы

Сплошная заливка, изображение или градиент — фон задаётся свойством background.

.hero {
  background-color: #1e3a8a;
  background-image: url("images/banner.jpg");
  background-size: cover;          /* растянуть и обрезать */
  background-position: center;
  background-repeat: no-repeat;
}

.avatar {
  background: linear-gradient(135deg, #2563eb, #1e3a8a);
}

Скругление, тени и outline

.btn {
  border-radius: 8px;              /* скругление углов */
  border: none;
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);  /* тень */
}

input:focus {
  outline: 2px solid #2563eb;      /* кольцо вокруг элемента */
}
border-radius со значением 50% превращает квадрат в круг — отличный способ сделать аватары.

Карточка целиком

.card {
  background: #ffffff;
  border: 1px solid #e5e7eb;
  border-radius: 10px;
  box-shadow: 0 1px 3px rgba(0,0,0,0.08), 0 4px 12px rgba(0,0,0,0.05);
  padding: 22px;
}

.card:hover {
  transform: translateY(-4px);
  box-shadow: 0 8px 24px rgba(0,0,0,0.12);
}

6. Flexbox

Flexbox раскладывает элементы в одну строку или колонку и умеет растягивать их по осям. Отличный выбор для меню, кнопок и рядов карточек.

.header-inner {
  display: flex;
  align-items: center;              /* по вертикали */
  justify-content: space-between;   /* кнопки по краям */
  flex-wrap: wrap;                  /* перенос на малом экране */
  gap: 20px;                        /* расстояние между */
}

.menu-item {
  flex-grow: 1;                     /* занимать лишнее место */
}
СвойствоЗначенияНазначение
flex-directionrow / columnнаправление раскладки
justify-contentstart / center / space-betweenвыравнивание по главной оси
align-itemscenter / stretchвыравнивание по поперечной оси
flex-wrapwrap / nowrapперенос элементов
gap10px / 1remрасстояние между элементами
flex-grow0 / 1 / 2как сильно элемент растёт

Пример ряда кнопок

.actions {
  display: flex;
  gap: 12px;
  justify-content: flex-end;
}

.actions .btn {
  flex-grow: 0;
  flex-shrink: 1;
}

7. CSS Grid

Grid — двухмерная сетка из строк и колонок. Идеален для целых страниц и галерей.

.layout {
  display: grid;
  grid-template-columns: 260px 1fr;   /* сайдбар + контент */
  gap: 28px;
  align-items: start;
}

.gallery {
  display: grid;
  grid-template-columns: repeat(3, 1fr);  /* три равные колонки */
  gap: 16px;
}

Функция repeat(3, 1fr) создаёт три равные колонки. Минимум 1fr означает «одна доля свободного места».

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

.site {
  display: grid;
  grid-template-areas:
    "header header"
    "sidebar main"
    "footer footer";
  grid-template-columns: 260px 1fr;
}

.site header { grid-area: header; }
.site aside  { grid-area: sidebar; }
.site main   { grid-area: main; }
.site footer { grid-area: footer; }
Для контента по центру ячейки используй justify-items: center и align-items: center — отлично подходит для огромных кнопок-плиток.

8. Позиционирование

Свойство position управляет тем, как элемент располагается относительно других.

ЗначениеПоведение
staticпо умолчанию, обычный поток
relativeсдвиг без выпадения из потока
absoluteпривязан к ближайшему relative-предку
fixedзакреплён относительно окна браузера
stickyприлипает при прокрутке
.badge {
  position: absolute;
  top: -10px;
  right: -10px;
  z-index: 10;               /* поверх остальных */
}

.card {
  position: relative;        /* станет опорой для badge */
}

.header {
  position: sticky;
  top: 0;                    /* шапка прилипает к верху */
}

.loader {
  position: fixed;
  bottom: 20px;
  right: 20px;
}
Чем больше z-index, тем выше элемент. Он работает только у позиционированных элементов (relative, absolute, fixed, sticky).

9. Анимации и переходы

transition плавно меняет свойства при наведении, а @keyframes задаёт сложную анимацию по ключевым кадрам.

Переходы

.btn {
  background: #2563eb;
  transition: background 0.2s, transform 0.2s;
}

.btn:hover {
  background: #1d4ed8;
  transform: scale(1.05);          /* увеличение */
}

.icon {
  transition: transform 0.3s;
}
.icon:hover {
  transform: rotate(90deg);        /* поворот */
}

Анимация @keyframes

@keyframes fade-in {
  from { opacity: 0; transform: translateY(20px); }
  to   { opacity: 1; transform: translateY(0); }
}

.modal {
  animation: fade-in 0.4s ease-out;
}

@keyframes pulse {
  0%, 100% { opacity: 1; }
  50%      { opacity: 0.4; }
}

.spinner {
  animation: pulse 1.5s infinite;
}

Сокращённая запись: animation: имя длительность функция-времени количество-повторов.

10. Адаптивность и медиазапросы

Медиазапросы применяют стили только при выполнении условия — например, на узких экранах.

/* базовые стили для мобильных (mobile-first) */
.gallery {
  display: grid;
  grid-template-columns: 1fr;
}

/* планшеты и выше */
@media (min-width: 768px) {
  .gallery {
    grid-template-columns: repeat(2, 1fr);
  }
}

@media (max-width: 900px) {
  .layout {
    grid-template-columns: 1fr;    /* сайдбар уходит вверх */
  }
}

Адаптивные изображения и единицы

img {
  max-width: 100%;       /* картинка не вылезет за блок */
  height: auto;
}

.hero {
  min-height: 100vh;     /* высота экрана */
  width: 80vw;           /* 80% ширины экрана */
}

p {
  font-size: 1rem;       /* относительно базового 16px */
}

.box {
  padding: 1em;          /* относительно текущего шрифта */
}
Подход mobile-first означает: сначала пишем стили для маленького экрана, затем медиазапросами с min-width добавляем стили для больших. Так базовый код проще и быстрее грузится.

11. Псевдоклассы и переменные

CSS-переменные (custom properties) объявляются в :root и используются через var(). Одна правка в одном месте — и весь сайт обновился.

:root {
  --accent: #2563eb;
  --accent-dark: #1d4ed8;
  --text: #1f2937;
  --muted: #6b7280;
  --radius: 10px;
  --shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
}

.btn {
  background: var(--accent);
  color: #fff;
  border-radius: var(--radius);
  box-shadow: var(--shadow);
}

.btn:hover {
  background: var(--accent-dark);
}

Переменные можно переопределять внутри любого блока. Например, задав их для .dark-theme, получишь тёмную тему без переписывания остальных правил.

Часто используемые псевдоклассы

.nav a:first-child { margin-left: 0; }
.nav a:last-child { margin-right: 0; }
li:nth-child(even) { background: #f1f5f9; }

input:focus {
  border-color: var(--accent);
  outline: none;
}

/* тёмная тема по одному классу */
.dark-theme {
  --text: #f8fafc;
  --accent: #60a5fa;
}
Благодаря переменным достаточно изменить пару значений в :root, чтобы обновить цвета, отступы и радиусы всех кнопок и карточек сайта. Это большой шаг к чистому поддерживаемому коду.

12. Контейнерные запросы

Медиазапросы зависят от размера окна. Контейнерные запросы реагируют на размер родителя — компонент адаптируется сам, где бы его ни поставили:

.card-grid {
  container-type: inline-size;
}

.card {
  display: grid;
  grid-template-columns: 1fr;
}

@container (min-width: 400px) {
  .card {
    grid-template-columns: 1fr 2fr;
  }
}
Задай контейнеру container-name, чтобы запросы не пересекались между вложенными компонентами.
Поддержка @container широкая с 2023 года; fallback — обычные media-запросы для старых браузеров.

13. Полезные функции: calc, clamp, min, max

Функции CSS считают значения на лету — без JavaScript:

/* смешиваем единицы */
width: calc(100% - 40px);

/* резиновый шрифт: 16px..24px, 50% от ширины экрана */
font-size: clamp(16px, 4vw, 24px);

/* минимум/максимум из списка */
padding: min(24px, 5vw);
margin-right: max(16px, 2vw);
ФункцияЧто делаетПример
calc()арифметика длин и процентов100% - 2rem
clamp()три точки: min, идеал, max1rem, 2vw, 2rem
min()/max()меньшее/большее из значенийmin(90%, 1200px)
clamp() заменяет «медиазапрос на каждый размер шрифта»: интервал указан одной строкой.

14. Тёмная тема: prefers-color-scheme

Включаем стили под системную тему пользователя:

@media (prefers-color-scheme: dark) {
  :root {
    --bg: #0f172a;
    --text: #f8fafc;
    --accent: #60a5fa;
  }
}

Надёжная схема — хранить «переменные дизайна» в CSS-кастомных свойствах (раздел 11) и менять только значения:

Не фиксируй цвет фона только в body: фон окна до загрузки страницы должен совпадать с темой, иначе заметно мигает.

15. Доступность и семантика

CSS не только украшает — он делает интерфейс доступным:

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    transition-duration: 0.01ms !important;
  }
}
Слово «просто сделай контрастнее» оборачивается дизайном, который нравится большему количеству людей — доступность выгодна всем.

16. Трансформации и 3D

Свойство transform двигает, вращает и масштабирует элемент, не ломая поток документа:

.card:hover {
  transform: translateY(-4px) scale(1.02);
  transition: transform 0.2s ease;
}
.flip { perspective: 800px; }
.flip:hover { transform: rotateY(180deg); }
Не перегружай интерфейс 3D-эффектами: анимации, которые не служат цели, утомляют и отвлекают от контента.

17. Изображения: object-fit и адаптивные наборы

Раз-у раз картинки «растягиваются» некрасиво. object-fit управляет вписыванием фото в контейнер:

.photo {
  width: 100%; height: 300px;
  object-fit: cover;      /* обрезать по центру */
}
<img src="photo-sm.jpg"
     srcset="photo-sm.jpg 480w, photo-lg.jpg 1024w"
     sizes="(max-width: 600px) 100vw, 600px"
     width="600" height="400" alt="Городской пейзаж">
Alt-текст обязателен: сломанный картинкой пользователь скринридера узнает, что на экране.

18. Веб-шрифты и типографика

Подключение шрифта через @font-face позволяет показывать брендовый шрифт на любом устройстве:

@font-face {
  font-family: 'MyFont';
  src: url('myfont.woff2') format('woff2');
  font-display: swap;   /* текст видим сразу, шрифт подменится */
}
body { font-family: 'MyFont', system-ui, sans-serif; }
Проверяй, что выбранный шрифт лицензионно разрешает веб-использование: бесплатный для скачивания ≠ бесплатный для сайта.

19. Современные селекторы: :is(), :where(), :has()

Условные группы селекторов сокращают дублирование кода и специфику регулировки:

/* :is() — специфику берёт самый "весомый" из списка */
:is(h1, h2, .title) { margin-top: 1.5em; }

/* :where() — специфика всегда нулевая, легко переопределить */
:where(article, aside) p { line-height: 1.6; }

/* :has() — родитель, если внутри что-то есть */
.card:has(img) { padding: 0; }
«Прогрессивное улучшение»: если :has() не сработал в старом браузере, применятся только базовые стили — вёрстка не сломается.

20. Анимации, привязанные к скроллу

Параллакс и прогресс-бары без JavaScript — реальность. Основы scroll-driven анимаций:

@keyframes fadeUp { from { opacity: 0; } to { opacity: 1; } }
.card { animation: fadeUp linear both; animation-timeline: view(); }
Держи такие анимации лёгкими: используй transform/opacity, иначе будет джиттер и расход GPU.

21. Каскадные слои: обуздаем специфичность

Специфичность решает, но управлять ей трудно. @layer задаёт порядок каскада явно:

@layer reset, base, components, utilities;
@layer base { h2 { margin-block: 1em; } }
@layer components { .card h2 { margin-block: 0.5em; } }
Слои решают войну «мой CSS vs библиотека»: оберни чужой код в слой и переопределяй спокойно.

22. Производительность стилей: составь, а не крась

Браузер пересчитывает стили и перерисовывает слои. Снижай цену изменений:

.feed-item { content-visibility: auto; contain-intrinsic-size: 400px; }
.will-anim { will-change: opacity; }
Не сыпь will-change на всё: каждый «обещанный слой» ест память GPU. Ставь только на то, что реально движется.

23. Чек-лист перед сдачей вёрстки

Финальная проверка из пунктов ниже — 15 минут, которые экономят дни правок:

  1. вёрстка на 320px и 1920px без горизонтального скролла;
  2. шрифты с font-display: swap и прелоадом;
  3. фокус-полосы видны, контраст текста ≥ 4.5:1;
  4. изображения с aspect-ratio и loading="lazy";
  5. анимации уважают prefers-reduced-motion.
@media (prefers-reduced-motion: reduce) {
  * { animation: none !important; }
}
Прогони Lighthouse из курса Lighthouse и DevTools из Chrome DevTools: цифры подтвердят глаза.

24. БЭМ и именование классов

Классы btn, btn-blue, text-left быстро превращаются в хаос. Методология БЭМ (block–element–modifier) даёт предсказуемые имена и переиспользуемые блоки:

card            /* блок */
card__title     /* элемент блока */
card__price     /* элемент блока */
card--featured  /* модификатор блока */
card__title--big /* модификатор элемента */
<div class="card card--featured">
  <h3 class="card__title card__title--big">Премиум</h3>
  <p class="card__price">990 ₽/мес</p>
</div>

.card { border: 1px solid #e5e7eb; padding: 20px; }
.card--featured { border-color: var(--accent); }
.card__title { font-size: 1.2rem; }
.card__price { color: var(--text-muted); }
БЭМ не обязателен к букве — важна система. Любая единая договорённость (БЭМ, utility-first, соседние классы) лучше разрозненных имён, придуманных «на ходу».
Utility-first подход — в уроке Tailwind CSS; классический БЭМ локально удобнее начинающим и в крупных проектах.

25. Логические свойства: направление не важно

Физические свойства (left, padding-left) работают в языках слева-направо. Логические (inline/block) привязаны к направлению текста и «зеркалятся» в RTL-языках автоматически:

/* вместо margin-left / margin-right */
margin-inline: auto;              /* inline — горизонталь, block — вертикаль */
padding-block: 12px;
inset-inline-start: 16px;         /* аналог left */
text-align: start;                /* аналог left, но уважает направление */
border-inline-end: 2px solid;     /* граница «в конце строки» */
ФизическоеЛогическое
margin-left / rightmargin-inline-start / end
margin-top / bottommargin-block-start / end
padding-left / rightpadding-inline-start / end
width / heightinline-size / block-size
top / left/right/bottominset-block / inset-inline
Для обычных русских сайтов разница не видна. Логические свойства выручают при локализации на иврит/арабский и делают код «умнее» без лишних правил.
Не смешивай подходы без нужды: гибрид физических и логических свойств в одном элементе сбивает с толку. Выберите один стиль на проект.
Логические свойства особенно удобны для библиотек и многоязычных проектов: вёрстка не ломается при переключении направления текста.

26. Мелкие, но мощные: scroll-snap, aspect-ratio, filter, clip-path

Несколько свойств, которые часто упускают в базовых курсах, а без них вёрстка «по-взрослому» не обходится.

scroll-snap: аккуратная прокрутка

.carousel {
  scroll-snap-type: x mandatory;   /* примагнитить при прокрутке */
  overflow-x: auto;
}
.carousel .slide { scroll-snap-align: start; }

aspect-ratio и filter

.video { aspect-ratio: 16 / 9; }     /* блок не «прыгает» */
img.gray { filter: grayscale(1); }
img.gray:hover { filter: none; }

clip-path и accent-color

.banner { clip-path: polygon(0 0, 100% 0, 100% 80%, 0 100%); }
input[type="checkbox"] { accent-color: var(--accent); }
aspect-ratio + max-width: 100% дают резиновые медиаблоки, которые резервируют место ещё до загрузки картинки.
clip-path обрезает визуально, но не «сам контент»: клики, тень и инспекция охватывают видимую форму. Для реального интерактива за пределами фигуры — отдельная логика.

27. :focus-visible и компания: стили для клавиатуры

Про :hover и :focus говорят часто, но при вёрстке кнопок забывают divide между кликом мышью и попаданием по Tab. Состояние фокуса, видимое пользователю с клавиатуры, даёт :focus-visible:

a:focus-visible,
button:focus-visible,
input:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

Аттрибут-условия :not(), ::selection и ::marker закрывают остальные «мелкие» сценарии:

.nav a:not(:last-child) { margin-right: 12px; }
::selection { background: var(--accent-light); }
li::marker { color: var(--accent); }
Способ проверить доступность фокуса на практике: закройте мышку рукой и пройдитесь по странице клавишами Tab — каждое интерактивное место должно быть видно.
Не снимай outline «чтобы красиво»: убрав контур фокуса, вы оставляете клавиатурного пользователя без ориентира (раздел 15 этого курса).

28. Структура CSS-файлов в проекте

Один файл на 3000 строк сложно поддерживать. Раскладывайте стили по смыслу — действует правило «понятно новому человеку за минуту»:

css/
├── base/      /* переменные, сброс, типографика из ;root */
├── layout/    /* header, footer, netki, контейнеры */
├── components/ /* переиспользуемые блоки: buttons, cards */
├── pages/     /* только страницеспецифичные правила */
└── utils/     /* хелперы: .visually-hidden, .text-muted */
/* components/buttons.css */
/* ===== Кнопки ===== */
.btn { display: inline-block; padding: 10px 22px; border-radius: 8px; }
.btn--primary { background: var(--accent); color: #fff; }
.btn--ghost { background: transparent; border: 1px solid var(--accent); }
Сборка нескольких файлов в один — задача сборщика (Vite/Webpack из Vite и Webpack) или препроцессора-импорта (Sass).
Правило «один класс — одна задача» и БЭМ из раздела 24 напрямую помогают структурировать компонентные файлы.

Что дальше

Теперь ты знаешь, как устроен CSS: от селекторов и box model до flexbox, grid, анимаций, БЭМ и логических свойств. Попрактикуйся на реальном проекте — свёрстай карточку, кнопку и шапку из примеров выше в браузере, проверьте себя в тестах по HTML и CSS и соберите целую страницу в Практике: лендинг. Углубиться в раскладку и анимации можно в Flexbox и Grid и CSS-анимации.

← Вернуться к курсам