Как делать12 октября 2026 г.8 мин чтения
Справочник разработчикаШаг 4 из 8

CSS: справочник селекторов, единиц, Flexbox и Grid

Коротко

Шпаргалка собирает то, что приходится вспоминать чаще всего: селекторы и расчёт специфичности (ID-CLASS-TYPE), единицы rem, em, %, vw, dvh, ch и функцию clamp(), box-sizing и позиционирование, свойства Flexbox и Grid, переменные, медиа- и контейнерные запросы и рецепты центрирования. Каждый фрагмент кода проверен в браузере, а статус поддержки новых возможностей дан по Baseline на дату проверки.

СправочникУровень: НачальныйСправочник CSS

После материала вы сможете

  • посчитать специфичность селектора, включая :is(), :where() и :has(), и понять, какое правило победит
  • выбрать единицу (rem, em, %, dvh, ch) и задать гибкий размер через clamp()
  • найти свойство Flexbox или Grid под задачу и отцентрировать блок одним из проверенных рецептов

Проверено на

Microsoft Edge 155 + Playwright 1.64web-features 3.42 (Baseline)

Сверено с документацией: 12 октября 2026 г.

Содержание
  1. 01Селекторы: от простых до :is(), :where() и :has()
  2. 02Специфичность: как посчитать вес селектора
  3. 03Единицы и функции размера
  4. 04Box model и позиционирование
  5. 05Flexbox и Grid: свойства
  6. 06Переменные, медиа- и контейнерные запросы
  7. 07Современные возможности и их поддержка
  8. 08Центрирование и частые ловушки

Селекторы: от простых до :is(), :where() и :has()

Селектор говорит браузеру, к каким элементам применить правило. Комбинаторы (пробел, >, +, ~) связывают селекторы по положению в дереве документа, псевдоклассы (:hover) описывают состояние, псевдоэлементы (::before) — часть элемента, которой нет в HTML.

*

Что выбирает
все элементы
Пример
* { margin: 0; }

p

Что выбирает
элементы по тегу
Пример
p { line-height: 1.6; }

.card

Что выбирает
элементы с классом
Пример
.card { padding: 16px; }

#app

Что выбирает
элемент с id
Пример
#app { min-height: 100dvh; }

[type="email"]

Что выбирает
по атрибуту и значению
Пример
input[type="email"]

A B

Что выбирает
B где угодно внутри A
Пример
nav a

A > B

Что выбирает
B — прямой потомок A
Пример
ul > li

A + B

Что выбирает
B сразу после A
Пример
h2 + p

A ~ B

Что выбирает
все B после A на одном уровне
Пример
h2 ~ p

:hover, :focus-visible

Что выбирает
состояние элемента
Пример
a:hover, button:focus-visible

:nth-child(2n)

Что выбирает
по номеру среди соседей
Пример
tr:nth-child(2n)

::before, ::after

Что выбирает
псевдоэлемент до или после содержимого
Пример
.req::after { content: "*"; }

:is(A, B)

Что выбирает
любой из списка; вес — самого тяжёлого аргумента
Пример
:is(h1, h2) a

:where(A, B)

Что выбирает
то же, но с весом 0
Пример
:where(ul, ol) li

:not(A)

Что выбирает
всё, что не подходит под A
Пример
li:not(:last-child)

A:has(B)

Что выбирает
A, внутри или рядом с которым есть B
Пример
.card:has(img)

:has() впервые позволил выбрать родителя или предыдущий элемент по тому, что идёт дальше. Три типовых приёма — раскладка карточки по наличию картинки, подсветка подписи у незаполненного поля и «неактивная» кнопка формы с ошибками:

has.css
/* Карточка с картинкой — в две колонки, без картинки — как обычно */
.card:has(img) {
  display: grid;
  grid-template-columns: 120px 1fr;
  gap: 16px;
}

/* Подпись над незаполненным обязательным полем */
label:has(+ input:invalid) {
  color: crimson;
}

/* Кнопка отправки тускнеет, пока в форме есть ошибки */
form:has(:invalid) button[type="submit"] {
  opacity: 0.5;
}
Проверено в Edge 155: display: grid только у карточки с <img>, подпись crimson и кнопка с opacity: 0.5, пока обязательное поле пустое; после ввода — обычный вид.

Специфичность: как посчитать вес селектора

Когда несколько правил задают одно свойство, браузер сравнивает специфичность — три числа ID-CLASS-TYPE. Сравнение идёт слева направо: один ID сильнее любого числа классов. При равном весе побеждает правило, которое стоит ниже. Специфичность сравнивается только внутри одного источника и слоя каскада.

*

Вес
0-0-0
Почему
универсальный селектор веса не добавляет

ul li

Вес
0-0-2
Почему
два тега; комбинаторы не считаются

.item, [type="email"], :hover

Вес
0-1-0
Почему
класс, атрибут и псевдокласс — в одной колонке

li.item

Вес
0-1-1
Почему
класс + тег

a::before

Вес
0-0-2
Почему
псевдоэлемент считается как тег

#nav .item

Вес
1-1-0
Почему
ID побеждает даже 11 классов

:not(.active)

Вес
0-1-0
Почему
сам :not() без веса, считается аргумент

:is(#nav, .menu) li

Вес
1-0-1
Почему
берётся самый тяжёлый аргумент, даже если совпал .menu

:where(#nav) li

Вес
0-0-1
Почему
:where() всегда 0

style="…"

Вес
выше любого селектора
Почему
перебивается только !important
specificity.css
nav a              { color: gray; }  /* 0-0-2 */
.menu a            { color: black; } /* 0-1-1 — сильнее */
:where(.menu) a    { color: red; }   /* 0-0-1 — :where() не добавляет веса */
:is(.menu, #top) a { color: blue; }  /* 1-0-1 — вес самого «тяжёлого» аргумента */
Все четыре правила совпадают с <nav class="menu"><a>. В Edge 155 ссылка синяя: :is(.menu, #top) получил вес ID, хотя #top на странице нет. Без последней строки — чёрная.
  • Порядок решения конфликта: важность (!important) и источник → слой @layer → специфичность → порядок в коде.
  • Стили вне слоёв сильнее стилей в любом @layer; из двух слоёв сильнее объявленный позже.
  • Сбросы и базовые стили пишите через :where() — их перебьёт любой класс без гонки весов.
  • !important и ID в стилях компонентов — последнее средство: их можно перебить только тем же оружием.

Единицы и функции размера

px

От чего считается
CSS-пиксель
Где удобна
рамки, тени, мелкие точные размеры

rem

От чего считается
font-size корня (html); по умолчанию обычно 16px, пользователь может изменить
Где удобна
шрифты, отступы, брейкпоинты

em

От чего считается
font-size самого элемента; внутри font-size — родителя
Где удобна
padding кнопки, иконка рядом с текстом

%

От чего считается
размер содержащего блока; padding и margin в % — от его ширины
Где удобна
ширина колонок, отступы-пропорции

vw, vh

От чего считается
1% ширины / высоты окна; vh равен lvh
Где удобна
полноэкранные блоки на десктопе

dvh, svh, lvh

От чего считается
1% высоты окна: динамической, малой, большой — с учётом панелей мобильного браузера
Где удобна
первый экран на телефоне

ch

От чего считается
ширина символа «0» в шрифте элемента
Где удобна
max-width текста

fr

От чего считается
доля свободного места в Grid
Где удобна
колонки сетки

cqi, cqw

От чего считается
1% размера контейнера запроса
Где удобна
типографика внутри компонента
units.css
html   { font-size: 100%; }  /* 1rem = размер из настроек браузера, обычно 16px */
.title { font-size: clamp(1.5rem, 1rem + 2.5vw, 3rem); }  /* 24px…48px */
.text  { max-width: 65ch; }  /* около 65 символов в строке */
.btn   { font-size: 1.25rem; padding: 0.5em 1em; }  /* em — от своего font-size: 10px 20px */
.hero  { min-height: 100dvh; }  /* высота окна с учётом панелей мобильного браузера */
Проверено в Edge 155: заголовок 24px при ширине окна 320px, 36px при 800px, 48px при 1600px; 65ch = ширине 65 нулей (520px шрифтом по умолчанию); у кнопки padding: 10px 20px; .hero = высоте окна.

clamp(MIN, ЖЕЛАЕМОЕ, MAX) возвращает желаемое значение, пока оно между границами. min(a, b) берёт меньшее, max(a, b) — большее, calc() смешивает единицы: calc(100% - 2rem).

Box model и позиционирование

Блок состоит из содержимого, padding, border и margin. По умолчанию (content-box) width задаёт только содержимое, и отступы с рамкой прибавляются сверху. С border-box width — это внешний размер до рамки включительно.

box.css
*, *::before, *::after {
  box-sizing: border-box;
}

.box {
  width: 300px;
  padding: 20px;
  border: 2px solid;
  /* border-box: снаружи 300px, под контент 300 − 40 − 4 = 256px */
  /* content-box: снаружи было бы 300 + 40 + 4 = 344px */
}
Проверено: .box шириной 300px, под содержимое 256px; с content-box тот же блок — 344px.

static

В потоке?
да
От чего top/left
не действуют
Типичный случай
значение по умолчанию

relative

В потоке?
да, место сохраняется
От чего top/left
от своего обычного места
Типичный случай
точка отсчёта для absolute-потомков

absolute

В потоке?
нет
От чего top/left
от ближайшего предка с position не static
Типичный случай
значок, крестик закрытия

fixed

В потоке?
нет
От чего top/left
от окна; при transform/filter у предка — от него
Типичный случай
плавающая кнопка, оверлей

sticky

В потоке?
да
От чего top/left
от ближайшего предка с прокруткой; нужен top или другой отступ
Типичный случай
шапка таблицы, меню
position.css
.card   { position: relative; }  /* точка отсчёта для absolute-потомков */
.badge  { position: absolute; top: 8px; right: 8px; }

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

.overlay {
  position: fixed;
  inset: 0;  /* = top: 0; right: 0; bottom: 0; left: 0 — на всё окно */
}
Проверено в Edge 155: значок в 8px от верхнего правого угла карточки; шапка на top: 0 после прокрутки на 1500px; .overlay закрывает окно и до, и после прокрутки.

Flexbox и Grid: свойства

Flexbox раскладывает элементы по одной оси, Grid — по строкам и колонкам сразу. Подробный разбор с практикой — в уроке о Flexbox и Grid, здесь только «свойство → что делает».

display: flex

Кому
контейнер
Что делает
делает прямых потомков flex-элементами

flex-direction

Кому
контейнер
Что делает
главная ось: row (по умолчанию), column, row-reverse, column-reverse

flex-wrap

Кому
контейнер
Что делает
nowrap (по умолчанию) или перенос на новые строки — wrap

justify-content

Кому
контейнер
Что делает
распределение по главной оси: flex-start, center, space-between…

align-items

Кому
контейнер
Что делает
выравнивание по поперечной оси; по умолчанию stretch

align-content

Кому
контейнер
Что делает
распределение строк при wrap

gap

Кому
контейнер
Что делает
промежуток между элементами

flex

Кому
элемент
Что делает
flex-grow flex-shrink flex-basis: 1 = 1 1 0%, auto = 1 1 auto, none = 0 0 auto, без flex — 0 1 auto

align-self

Кому
элемент
Что делает
своё выравнивание по поперечной оси

order

Кому
элемент
Что делает
меняет только визуальный порядок; Tab и скринридер идут по HTML

margin-left: auto

Кому
элемент
Что делает
забирает свободное место и отталкивает элемент вправо
Flexbox
flex.css
.toolbar {
  display: flex;
  align-items: center;  /* по поперечной оси */
  gap: 12px;
  flex-wrap: wrap;
}
.toolbar .push { margin-left: auto; }  /* прижать этот и следующие элементы вправо */

.columns { display: flex; gap: 16px; }
.columns > * {
  flex: 1;        /* = 1 1 0%: равные доли */
  min-width: 0;   /* длинное содержимое не распирает колонку */
}
Проверено: последняя кнопка у правого края тулбара, элементы выровнены по центру; три колонки по 200px в контейнере 632px, хотя во второй строка из 400 символов. Без min-width: 0 вторая колонка растягивается больше 3000px.

grid-template-columns / -rows

Кому
контейнер
Что делает
треки: 200px 1fr, repeat(3, 1fr)

repeat(auto-fit, minmax(240px, 1fr))

Кому
контейнер
Что делает
столько колонок, сколько влезет; auto-fit растягивает их, auto-fill оставляет пустые треки

minmax(0, 1fr)

Кому
контейнер
Что делает
колонка не шире своей доли даже с длинным содержимым

grid-template-areas

Кому
контейнер
Что делает
макет именованными областями

grid-auto-rows

Кому
контейнер
Что делает
высота неявно созданных строк

justify-items / align-items / place-items

Кому
контейнер
Что делает
выравнивание элементов внутри ячеек

grid-area

Кому
элемент
Что делает
имя области из grid-template-areas

grid-column: 1 / -1

Кому
элемент
Что делает
от первой до последней линии — на всю ширину

grid-column: span 2

Кому
элемент
Что делает
занять две колонки

grid-template-columns: subgrid

Кому
вложенная сетка
Что делает
взять колонки родительской сетки
Grid
grid.css
.cards {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 240px), 1fr));
  gap: 16px;
}

.page {
  display: grid;
  grid-template-columns: 240px minmax(0, 1fr);
  grid-template-areas:
    "head head"
    "side main"
    "foot foot";
  gap: 16px;
}
.page > header { grid-area: head; }
.page > aside  { grid-area: side; }
.page > main   { grid-area: main; }
.page > footer { grid-area: foot; }

.wide { grid-column: 1 / -1; }  /* от первой до последней линии */
Проверено: карточек в ряду 1 / 3 / 4 при ширине окна 375 / 800 / 1280px; в .page шириной 1000px сайдбар 240px, main 744px даже с длинной строкой, шапка и подвал на всю ширину; .wide на весь ряд.

Переменные, медиа- и контейнерные запросы

Пользовательские свойства (custom properties, «CSS-переменные») начинаются с --, читаются через var() и наследуются потомками. Переопределите переменную на компоненте — и изменится всё, что её использует внутри.

vars.css
:root {
  --accent: #2563eb;
  --space: 16px;
}

.btn {
  background: var(--accent);
  padding: var(--space);
  color: var(--btn-text, white);  /* white, если --btn-text не задана */
}

.btn--danger {
  --accent: #dc2626;  /* переопределение действует внутри .btn--danger */
}
Проверено: у .btn фон #2563eb, у .btn--danger — #dc2626; цвет текста white по запасному значению и black, если --btn-text задана у предка.
queries.css
.list { display: grid; gap: 16px; }

@media (width >= 768px) {  /* то же, что (min-width: 768px) */
  .list { grid-template-columns: 1fr 1fr; }
}

@media (prefers-reduced-motion: reduce) {
  .fade { transition: none; }
}

.slot { container-type: inline-size; }  /* контейнер для @container */

@container (width > 480px) {
  .card { display: grid; grid-template-columns: 160px 1fr; }
}
Проверено: одна колонка .list при 767px, две при 768px; transition: none при prefers-reduced-motion: reduce; .card — сетка в контейнере 600px и обычный блок в 400px.

Что измеряет

@media
окно браузера и настройки устройства
@container
размер ближайшего предка-контейнера

Что нужно объявить

@media
ничего
@container
container-type: inline-size (или size) у предка

Для чего

@media
раскладка страницы, тема, prefers-reduced-motion
@container
компонент, который стоит то в узкой колонке, то в широкой

Синтаксис диапазона

@media
(width >= 768px) = (min-width: 768px)
@container
(width > 480px)

Современные возможности и их поддержка

Baseline — сводка поддержки в Chrome, Edge, Firefox и Safari (десктоп и мобильные). «Широко доступно» — функция работает во всех этих браузерах не меньше 2,5 лет; «Недавно доступно» — только в последних версиях; «Ограниченно» — ещё не везде. Статусы ниже сняты 12.10.2026 с MDN и пакета web-features 3.42; они меняются — перед использованием проверьте значок Baseline на странице свойства в MDN.

:is(), :where(), :focus-visible

Что даёт
короткие списки селекторов, нулевой вес, фокус только с клавиатуры
Baseline на 12.10.2026
широко доступно

clamp(), min(), max()

Что даёт
размеры без медиазапросов
Baseline на 12.10.2026
широко доступно

aspect-ratio, gap у Flexbox

Что даёт
пропорции блока, промежутки без margin
Baseline на 12.10.2026
широко доступно

dvh, svh, lvh

Что даёт
высота окна с учётом панелей браузера
Baseline на 12.10.2026
широко доступно

@layer

Что даёт
управляемый порядок каскада
Baseline на 12.10.2026
широко доступно

Синтаксис (width >= 768px)

Что даёт
диапазоны в медиазапросах
Baseline на 12.10.2026
широко доступно

@container (размер)

Что даёт
адаптивность компонента
Baseline на 12.10.2026
широко доступно

color-mix()

Что даёт
смешивание цветов в CSS
Baseline на 12.10.2026
широко доступно

subgrid

Что даёт
вложенная сетка по линиям родителя
Baseline на 12.10.2026
широко доступно

:has()

Что даёт
выбор родителя и предыдущего элемента
Baseline на 12.10.2026
широко доступно

Вложенность &

Что даёт
вложенные правила без препроцессора
Baseline на 12.10.2026
широко доступно

text-wrap: balance

Что даёт
ровные строки заголовков
Baseline на 12.10.2026
недавно доступно

@starting-style, light-dark()

Что даёт
анимация появления, цвета для светлой и тёмной темы
Baseline на 12.10.2026
недавно доступно

@scope, field-sizing

Что даёт
область действия стилей, поле по размеру текста
Baseline на 12.10.2026
недавно доступно

Контейнерные запросы по стилю

Что даёт
@container style(--x: y)
Baseline на 12.10.2026
недавно доступно

Анимации по прокрутке (animation-timeline)

Что даёт
анимация, привязанная к прокрутке
Baseline на 12.10.2026
ограниченно
modern.css
/* Вложенность без препроцессора */
.card {
  padding: 16px;
  & .title { font-size: 1.25rem; }
  &:hover { outline: 2px solid; }
}

/* Слои каскада: более поздний слой сильнее, специфичность не важна */
@layer reset, components;
@layer reset      { #app button { margin: 0; } }  /* 1-0-1 */
@layer components { .btn { margin: 8px; } }       /* 0-1-0 — побеждает */

/* Ветка только для браузеров с поддержкой :has() */
@supports selector(:has(a)) {
  .card:has(img) { display: grid; grid-template-columns: 120px 1fr; }
}
Проверено в Edge 155: .title — 20px через вложенность, у кнопки margin: 8px из более позднего слоя, хотя правило #app button тяжелее; ветка @supports применилась.

Центрирование и частые ловушки

center.css
/* 1. Grid: по обеим осям одной строкой */
.center-grid {
  display: grid;
  place-items: center;
}

/* 2. Flex: то же, плюс удобно для нескольких элементов в ряд */
.center-flex {
  display: flex;
  justify-content: center;
  align-items: center;
}

/* 3. Контейнер страницы по горизонтали */
.container {
  max-width: 1200px;
  margin-inline: auto;
}

/* 4. Поверх родителя (модалка, значок) */
.center-abs-parent { position: relative; }
.center-abs {
  position: absolute;
  top: 50%;
  left: 50%;
  translate: -50% -50%;
}
Проверено: во всех трёх вариантах центр дочернего блока совпадает с центром родителя (смещение 0px); .container шириной 1200px стоит с отступом 40px в окне 1280px.

один блок по обеим осям

Рецепт
display: grid; place-items: center

несколько элементов в ряд

Рецепт
display: flex; justify-content: center; align-items: center

контейнер страницы

Рецепт
max-width + margin-inline: auto

строчный текст и кнопки внутри блока

Рецепт
text-align: center

поверх содержимого

Рецепт
position: absolute; top: 50%; left: 50%; translate: -50% -50%

top и z-index не действуют

Причина
у элемента position: static
Исправление
position: relative

sticky не прилипает

Причина
нет top или у предка overflow: hidden
Исправление
задать top, убрать overflow у предка

z-index: 9999 под соседом

Причина
элемент в другом контексте наложения (у родителя свой z-index)
Исправление
поднимать родителя, а не ребёнка

fixed отсчитывается не от окна

Причина
у предка transform, filter или translate
Исправление
вынести элемент из такого предка

width: 100% + padding вылезает

Причина
content-box
Исправление
box-sizing: border-box

колонку распирает длинное слово или код

Причина
минимальная ширина flex- и grid-элемента — по содержимому
Исправление
min-width: 0 или minmax(0, 1fr)

100vh на телефоне выше экрана

Причина
vh считается от большой высоты окна
Исправление
100dvh или 100svh

@container не срабатывает

Причина
у предка нет container-type
Исправление
container-type: inline-size

Готовые утилиты для всего этого есть в Tailwind CSS: grid place-items-center, mx-auto, min-w-0, @container, — разбор в уроке о Tailwind CSS.

Как проверено4 · пройденосверено 12 октября 2026 г.
  • запущено, работает

    has.css, specificity.css, units.css, box.css, position.css, flex.css, grid.css, vars.css, queries.css, center.css (RU и EN-версии комментариев)

    check.mjs: Microsoft Edge 155.0.4283.45 через Playwright 1.64 (channel msedge), getComputedStyle и getBoundingClientRect — 52 проверки для каждого из двух наборов файлов, 0 ошибок консоли. Ключевые значения: :is(.menu,#top) a побеждает (синий); clamp 24/36/48px при 320/800/1600px; 65ch = 520px; padding 10px 20px; 100dvh = 700px; border-box 300/256, content-box 344; значок 8/8px; sticky y=0 после прокрутки; колонки flex по 200px с min-width:0 и >3000px без него; flex: 1 → 1 1 0%; auto-fit 1/3/4 колонки при 375/800/1280; области 240/744; var() в @media не работает; @media 767→1, 768→2; reduced-motion 0s; @container 400→block, 600→grid, без container-type — block; три способа центрирования со смещением 0px

  • запущено, работает

    modern.css (вложенность, @layer, @supports)

    modern-check.mjs, Edge 155: .title 20px, margin 8px из более позднего слоя против #app button, @supports-ветка применилась, :hover даёт outline 2px; RU и EN

  • запущено, работает

    таблицы селекторов и специфичности

    sel-table.mjs: 12 селекторов из таблицы через querySelectorAll + ::after content; spec-table.mjs: 10 пар правил (более слабое ниже по коду) + inline против #id и !important против inline — все победители совпали с таблицей

  • запущено, работает

    утверждения таблиц (единицы, flex/grid, ловушки)

    props.mjs, Edge 155: em/rem/%/vw; flex auto/none/по умолчанию; stretch, space-between; order не меняет порядок Tab; span 2, grid-auto-rows, auto-fill vs auto-fit 100/500px; CSS.supports для subgrid, :has, container-type, dvh, color-mix, text-wrap: balance; @layer и стили вне слоёв; top у static; sticky в overflow:hidden; z-index 9999 под соседом; fixed внутри transform; width:100%+padding = 340px — 34 проверки

«Запущено» — код выполнен во временном проекте или контейнере, вывод в статье взят из прогона. «Частично» — проверено с заглушками вместо внешних сервисов. «Не запускалось» — нужны устройство, аккаунт или ключ; шаги сверены с официальной документацией. Файлы проверочного проекта и логи запусков сохранены в архиве InterLAB.

Расскажите о задаче — мы изучим запрос и свяжемся с вами

Есть задача?
Обсудим и оценим — бесплатно.

Расскажите о продукте или проблеме. Предложим архитектуру, срок и стоимость первой версии после изучения задачи.

  • Оценка объёма и рисков до старта
  • NDA — по вашему или нашему шаблону
  • Старт работ в течение недели

Не присылайте через форму пароли, ключи доступа и исходный код — безопасную передачу доступа обсудим отдельно.

Нажимая кнопку, вы соглашаетесь с обработкой персональных данных.