🎨 CSS

Полный справочник: селекторы и специфичность, каскад и слои, блочная модель, flexbox, grid, позиционирование, единицы, цвета, типографика, адаптивность и container queries, переменные, анимации, паттерны и отладка.

Шпаргалки · Данные · #css #css3 #web #styles #responsive #flexbox #grid

Подключение и синтаксис

селектор { свойство: значение; другое-свойство: значение; }
<link rel="stylesheet" href="style.css">      <style>…</style>      <p style="color: red">           <!-- inline: избегайте -->
@import url("base.css");                      /* медленнее <link> */
/* комментарий */

Современные браузеры поддерживают вложенность, :has(), container queries, @layer, color-mix(): проверяйте на caniuse.com и MDN.

Селекторы

Селектор Выбирает
* все
p, .card, #main по тегу, классу, id
a, b любой из
ul li потомок любой глубины
ul > li прямой потомок
h2 + p следующий сосед
h2 ~ p все следующие соседи
[href], [type="text"], [href^="https"], [href$=".pdf"], [class*="btn"] по атрибуту
:hover, :focus, :focus-visible, :active, :disabled, :checked, :required, :invalid состояния
:first-child, :last-child, :nth-child(2n+1), :nth-of-type(3), :only-child, :empty позиция
:not(.x), :is(h1, h2), :where(...), :has(img) логические (:has родитель по содержимому)
::before, ::after, ::first-line, ::first-letter, ::placeholder, ::selection, ::marker псевдоэлементы (content обязателен)
& вложенность: .card { &:hover {} .title {} }

Каскад и специфичность

Правило побеждает по порядку: важность (!important) → слой (@layer) → специфичность → порядок в файле (позднее выигрывает).

Специфичность считается тройкой (id, классы/атрибуты/псевдоклассы, теги): #a .b p = (1,1,1) сильнее .a .b .c = (0,3,0). Inline-стили сильнее селекторов. :where() даёт нулевую специфичность, :is() берёт максимальную из списка.

@layer reset, base, components, utilities;           /* порядок слоёв задаёт приоритет, а не специфичность */
@layer components { .btn { padding: .5rem 1rem; } }

Избегайте !important и глубоких селекторов, держите специфичность низкой и ровной (классы, БЭМ).

Наследование

Наследуются: color, font-*, line-height, text-align, visibility, cursor, list-style. Не наследуются: размеры, поля, рамки, фон, позиционирование. Принудительно: inherit, initial, unset, revert.

Блочная модель

*, *::before, *::after { box-sizing: border-box; }    /* ширина включает padding и border */
.box {
  width: 300px; height: auto; min-width: 0; max-width: 100%;
  padding: 16px 24px;                   /* top/bottom left/right (1–4 значения по часовой стрелке) */
  margin: 0 auto;                       /* центрирование блока по горизонтали */
  border: 1px solid #ccc; border-radius: 8px;
  outline: 2px solid blue; outline-offset: 2px;
}

Схлопывание отступов: вертикальные margin соседних блоков объединяются (берётся больший). Не схлопываются во flex- и grid-контейнерах. Логические свойства (удобны для RTL): margin-inline, padding-block, inset-inline-start, inline-size, block-size.

display

Значение Поведение
block на всю ширину, с новой строки
inline в строке, без width/height и вертикальных отступов
inline-block в строке, но с размерами
flex / inline-flex гибкий контейнер (одно измерение)
grid / inline-grid сетка (два измерения)
none не отображается и не занимает места
contents убирает сам блок, оставляя детей
visibility: hidden скрыт, но место занимает

Flexbox

.row {
  display: flex;
  flex-direction: row;            /* row | column | row-reverse | column-reverse */
  flex-wrap: wrap;
  justify-content: space-between; /* по главной оси: flex-start | center | flex-end | space-around | space-evenly */
  align-items: center;            /* по поперечной: stretch | flex-start | center | flex-end | baseline */
  align-content: flex-start;      /* несколько строк */
  gap: 12px 16px;
}
.item { flex: 1 1 200px; }        /* grow shrink basis */
.item { flex: 1; }                /* равные доли */
.item { flex: none; }             /* фиксированный */
.item { align-self: flex-end; order: 2; margin-left: auto; }   /* margin-left: auto — прижать вправо */

Типичные приёмы: центрирование display: flex; place-items: center; justify-content: center;, «липкий» подвал (body { min-height: 100vh; display: flex; flex-direction: column } main { flex: 1 }), min-width: 0 у flex-элемента, чтобы длинный текст не распирал контейнер.

Grid

.grid {
  display: grid;
  grid-template-columns: 200px 1fr 2fr;                          /* fr — доли свободного места */
  grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));    /* адаптивные карточки без media */
  grid-template-rows: auto 1fr auto;
  gap: 16px;
  grid-template-areas:
    "header header"
    "sidebar main"
    "footer footer";
  place-items: center;
}
.header { grid-area: header; }
.wide  { grid-column: span 2; }          .item { grid-column: 1 / -1; grid-row: 2 / 4; }

auto-fill сохраняет пустые колонки, auto-fit растягивает элементы. subgrid наследует линии родителя. Выравнивание: justify-items, align-items, justify-content, align-content, place-*. Flexbox для одного ряда или колонки, grid для двумерной раскладки.

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

Значение Поведение
static по умолчанию, обычный поток
relative сдвиг от своего места; становится опорой для absolute внутри
absolute относительно ближайшего позиционированного предка, вне потока
fixed относительно окна
sticky прилипает при прокрутке (top: 0); нужен прокручиваемый предок без overflow: hidden
.overlay { position: fixed; inset: 0; z-index: 100; }       /* inset = top/right/bottom/left */
.badge { position: absolute; top: -4px; right: -4px; }

z-index работает у позиционированных элементов и flex/grid-детей; контексты наложения создают position + z-index, opacity < 1, transform, filter.

Единицы измерения

Единица Смысл
px пиксель
rem от размера шрифта html (удобно для масштабируемого интерфейса)
em от шрифта текущего элемента
% от размера родителя
vw, vh, vmin, vmax доли окна; dvh, svh, lvh учитывают панели мобильных браузеров
ch, ex ширина «0», высота «x» (max-width: 65ch для читаемых строк)
fr доля в grid
deg, turn, s, ms углы и время
width: clamp(280px, 90%, 1200px);            font-size: clamp(1rem, 2vw + .5rem, 1.5rem);        /* min, предпочтительное, max */
width: calc(100% - 2rem);                     height: min(50vh, 400px);     max(1rem, 2vw)

Цвета и фон

color: #1d4ed8;  color: rgb(29 78 216 / 80%);  color: hsl(221 83% 53%);  color: oklch(60% .2 260);  color: currentColor;
background: linear-gradient(135deg, #7c3aed, #2563eb);  background: radial-gradient(circle at top, #fff, transparent);
background: url(bg.jpg) center / cover no-repeat;       background-color: color-mix(in srgb, var(--brand) 20%, white);
opacity: .5;   mix-blend-mode: multiply;   backdrop-filter: blur(8px);   filter: grayscale(1) blur(2px);

Контраст текста не ниже 4.5:1 (WCAG AA).

Типографика

font-family: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;     /* системный стек */
font-size: 1rem;  font-weight: 400|600|700;  font-style: italic;  line-height: 1.5;  letter-spacing: .02em;
text-align: left|center|right|justify;  text-transform: uppercase;  text-decoration: underline dotted;
text-overflow: ellipsis; white-space: nowrap; overflow: hidden;                          /* обрезка одной строки */
display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden;   /* обрезка по числу строк */
word-break: break-word;  overflow-wrap: anywhere;  hyphens: auto;  text-wrap: balance;   tab-size: 2;
@font-face { font-family: "Inter"; src: url(inter.woff2) format("woff2"); font-display: swap; font-weight: 100 900; }

Рамки, тени, трансформации

border: 1px solid; border-radius: 50%; box-shadow: 0 4px 12px rgb(0 0 0 / .15), inset 0 0 0 1px #eee;   text-shadow: 0 1px 2px #0004;
transform: translate(10px, 20px) rotate(15deg) scale(1.1) skew(5deg);   transform-origin: top left;     /* не влияют на поток */
aspect-ratio: 16 / 9;    object-fit: cover;    object-position: center;     overflow: hidden | auto | scroll | clip;

Переходы и анимации

.btn { transition: transform .2s ease, background-color .2s; }
.btn:hover { transform: translateY(-2px); }

@keyframes fade-in { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: none; } }
.card { animation: fade-in .4s ease-out both; animation-delay: .1s; animation-iteration-count: infinite; }

@media (prefers-reduced-motion: reduce) { * { animation: none !important; transition: none !important; } }

Для плавности анимируйте transform и opacity (GPU), а не width, top, margin. Подсказка: will-change: transform только на время анимации. Прокрутка по ссылкам: scroll-behavior: smooth. Анимации по скроллу и переходы между страницами: animation-timeline: scroll(), View Transitions API.

Адаптивный дизайн

<meta name="viewport" content="width=device-width, initial-scale=1">      /* в HTML */

.container { width: min(100% - 2rem, 1200px); margin-inline: auto; }
img, video { max-width: 100%; height: auto; display: block; }

/* mobile first: базовые стили для телефона, расширяем */
.cards { display: grid; gap: 1rem; grid-template-columns: 1fr; }
@media (min-width: 640px)  { .cards { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 1024px) { .cards { grid-template-columns: repeat(3, 1fr); } }
@media (hover: hover) { .btn:hover { … } }            @media (pointer: coarse) { .btn { min-height: 44px; } }
@media (orientation: landscape) {}                     @media print { nav { display: none; } }

Типичные точки: 480, 640, 768, 1024, 1280 пикселей; выбирайте по содержимому. Container queries подстраивают компонент под размер своего контейнера:

.card-wrap { container-type: inline-size; container-name: card; }
@container card (min-width: 420px) { .card { display: flex; } }

Переменные и тёмная тема

:root {
  --brand: #7c3aed;  --gap: 1rem;  --radius: .5rem;
  --bg: #fff;  --text: #111;
  color-scheme: light dark;
}
@media (prefers-color-scheme: dark) { :root { --bg: #0b0b10; --text: #eee; } }
[data-theme="dark"] { --bg: #0b0b10; --text: #eee; }
body { background: var(--bg); color: var(--text); }
.btn { background: var(--brand, #333); padding: var(--gap); border-radius: var(--radius); }
@property --angle { syntax: "<angle>"; inherits: false; initial-value: 0deg; }       /* анимируемые переменные */

Переменные наследуются и переопределяются в любом селекторе, читаются из JavaScript: el.style.setProperty('--x', '10px').

Формы и интерактив

input, button, select, textarea { font: inherit; }
button:focus-visible, a:focus-visible { outline: 2px solid var(--brand); outline-offset: 2px; }     /* не убирайте outline без замены */
input:user-invalid { border-color: crimson; }          input[type="checkbox"] { accent-color: var(--brand); }
.btn:disabled { opacity: .5; cursor: not-allowed; }    ::placeholder { color: #888; }
textarea { resize: vertical; }                          a { text-underline-offset: .15em; }
caret-color: var(--brand);  user-select: none;  pointer-events: none;  touch-action: manipulation;  scroll-snap-type: x mandatory;

Типичные приёмы

/* центрирование */
.center { display: grid; place-items: center; min-height: 100vh; }
/* карточки без media-запросов */
.cards { display: grid; gap: 1rem; grid-template-columns: repeat(auto-fit, minmax(min(100%, 260px), 1fr)); }
/* кнопка-иконка и скрытие для визуальных, но не для скринридеров */
.sr-only { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; }
/* липкая шапка */
header { position: sticky; top: 0; z-index: 10; backdrop-filter: blur(8px); }
/* стек отступов */
.stack > * + * { margin-block-start: 1rem; }
/* разделитель */
.divider { border: 0; border-top: 1px solid color-mix(in srgb, currentColor 20%, transparent); }
/* скелетон */
.skeleton { background: linear-gradient(90deg, #eee 25%, #f5f5f5 50%, #eee 75%); background-size: 200% 100%; animation: shimmer 1.2s infinite; }
@keyframes shimmer { to { background-position: -200% 0; } }

Сброс и основа

*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }
body { margin: 0; line-height: 1.5; font-family: system-ui, sans-serif; -webkit-font-smoothing: antialiased; }
img, picture, svg, video { max-width: 100%; display: block; }

Готовые: modern-normalize, Josh Comeau's reset, normalize.css.

Организация CSS

Подход Суть
БЭМ .block__element--modifier, плоские селекторы
Utility-first Tailwind, UnoCSS: много мелких классов
CSS Modules локальные имена классов на компонент
CSS-in-JS styled-components, Emotion, vanilla-extract
Препроцессоры Sass / SCSS, Less (переменные, миксины, вложенность)
PostCSS autoprefixer, nesting, минификация

Современный CSS заменяет многое из препроцессоров: переменные, вложенность, color-mix, calc().

Отладка

DevTools (F12): панель «Styles» (откуда значение и что перебито), «Computed» (итог), блок «Layout» (flex/grid оверлеи), outline: 1px solid red на * для просмотра границ. Типичные причины «не применяется»: специфичность, опечатка, свойство не работает для этого display, перекрыто позднее правило, неверный путь к файлу, кэш (Ctrl+F5).

Частые ошибки

  • Забыт box-sizing: border-box и viewport.
  • Фиксированные высоты и размеры в px для текста.
  • 100vh на мобильных (используйте dvh).
  • overflow: hidden у предка ломает sticky.
  • Убран outline без замены (недоступно с клавиатуры).
  • Анимация width, height, top вместо transform.
  • Длинные селекторы и !important.
  • Горизонтальный скролл из-за элементов шире окна (max-width: 100%, min-width: 0).