CSS — стилизация веб-страниц
CSS (Cascading Style Sheets — каскадные таблицы стилей) отвечает за внешний вид страницы: цвета, шрифты, отступы, сетки и анимации. На этой странице ты научишься стилизовать карточки, кнопки и шапку сайта с нуля.
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>Каскад и приоритеты
Слово «каскад» означает порядок применения правил. При конфликте побеждает правило с большим приоритетом:
- Inline-стили — самый высокий приоритет.
- Селектор с id.
- Селектор с классом.
- Селектор по тегу.
- Правило, объявленное позже в файле, перекрывает более раннее при равной специфичности.
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 |
| класс, атрибут, :hover | 10 |
| id | 100 |
| style="..." inline | 1000 |
Комбинации складываются: .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-direction | row / column | направление раскладки |
| justify-content | start / center / space-between | выравнивание по главной оси |
| align-items | center / stretch | выравнивание по поперечной оси |
| flex-wrap | wrap / nowrap | перенос элементов |
| gap | 10px / 1rem | расстояние между элементами |
| flex-grow | 0 / 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; /* относительно текущего шрифта */
}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, чтобы запросы не пересекались между вложенными компонентами.- контроль: инлайн-размер, блок-размер, стили;
- работают для карточек, виджетов, шапок;
- отлично сочетаются с CSS Grid из раздела 7.
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, идеал, max | 1rem, 2vw, 2rem |
| min()/max() | меньшее/большее из значений | min(90%, 1200px) |
14. Тёмная тема: prefers-color-scheme
Включаем стили под системную тему пользователя:
@media (prefers-color-scheme: dark) {
:root {
--bg: #0f172a;
--text: #f8fafc;
--accent: #60a5fa;
}
}Надёжная схема — хранить «переменные дизайна» в CSS-кастомных свойствах (раздел 11) и менять только значения:
- тёмный фон + светлый текст с достаточным контрастом;
- тонкие шрифты на тёмном смотрятся хуже — добавь лёгкое увеличение толщины;
- картинки и тени: для тёмной темы мягче, без глубоких теней;
- учитывай флаг
color-schemeдля скроллбаров и форм.
body: фон окна до загрузки страницы должен совпадать с темой, иначе заметно мигает.15. Доступность и семантика
CSS не только украшает — он делает интерфейс доступным:
- контраст текста и фона: минимум 4.5:1 для текста;
- фокус: нельзя убирать outline полностью;
- движение:
prefers-reduced-motion: reduceотключает лишние анимации; - координация с
ariaи семантической разметкой из курса HTML; - минимальный размер кликабельных зон — 24×24px.
@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;
}rotate(45deg),scale(1.5),translate(x, y)— основные функции;transform-originзадаёт точку поворота (по умолчанию центр);- 3D: родителю —
perspective: 600px, карточке —rotateY()для «переворота»; - transform и opacity анимируются через GPU — для скользящих панелей используй их, а не top/left.
.flip { perspective: 800px; }
.flip:hover { transform: rotateY(180deg); }17. Изображения: object-fit и адаптивные наборы
Раз-у раз картинки «растягиваются» некрасиво. object-fit управляет вписыванием фото в контейнер:
.photo {
width: 100%; height: 300px;
object-fit: cover; /* обрезать по центру */
}cover— заполняет контейнер с обрезкой;contain— вписывает целиком;- для ретины:
srcsetс разными ширинами; <picture>+<source media>— разные картинки для мобильного и десктопа;- указывай
width/height, чтобы браузер резервировал место и страница не «прыгала».
<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="Городской пейзаж">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; }- формат woff2 — приоритет: меньше по весу, быстрее качается;
- подключай только нужные начертания (regular, bold), а не весь пакет;
font-display: swapне даёт «невидимому тексту» висеть в ожидании шрифта;- системные шрифты через
system-uiэкономят загрузку, если брендовый не критичен.
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()реализует «стили по наличию потомка» — например, отметить карточку с видео;- искомые: проверить, что поле формы пустое:
input:has(+ .error)сложно, но реально; - для старых браузеров давай базовое правило, а новое — через
@supports.
20. Анимации, привязанные к скроллу
Параллакс и прогресс-бары без JavaScript — реальность. Основы scroll-driven анимаций:
@keyframes fadeUp { from { opacity: 0; } to { opacity: 1; } }
.card { animation: fadeUp linear both; animation-timeline: view(); }animation-timeline: view()— срабатывание при появлении вьюпорта;scroll()— анимация относительно позиции скролл-контейнера;- без поддержки стиль просто не анимируется — вёрстка не ломается.
21. Каскадные слои: обуздаем специфичность
Специфичность решает, но управлять ей трудно. @layer задаёт порядок каскада явно:
@layer reset, base, components, utilities;
@layer base { h2 { margin-block: 1em; } }
@layer components { .card h2 { margin-block: 0.5em; } }- поздний слой всегда побеждает ранний — независимо от специфичности;
- сбрасывающий код клади в первый слой, утилиты — в последний;
- правило внутри слоя слабее правила вне слоёв — учитывай при импорте библиотек.
22. Производительность стилей: составь, а не крась
Браузер пересчитывает стили и перерисовывает слои. Снижай цену изменений:
- анимируй только transform/opacity — они на композиторе, а не в layout/paint;
content-visibility: auto— пропустить рендер невидимых блоков;contain: layout paint— изоляция области от «перерисовки мира».
.feed-item { content-visibility: auto; contain-intrinsic-size: 400px; }
.will-anim { will-change: opacity; }will-change на всё: каждый «обещанный слой» ест память GPU. Ставь только на то, что реально движется.23. Чек-лист перед сдачей вёрстки
Финальная проверка из пунктов ниже — 15 минут, которые экономят дни правок:
- вёрстка на 320px и 1920px без горизонтального скролла;
- шрифты с
font-display: swapи прелоадом; - фокус-полосы видны, контраст текста ≥ 4.5:1;
- изображения с
aspect-ratioиloading="lazy"; - анимации уважают
prefers-reduced-motion.
@media (prefers-reduced-motion: reduce) {
* { animation: none !important; }
}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); }- блок — самостоятельная сущность (кнопка, карточка, форма);
- элемент — часть блока, через двойное подчёркивание
__; - модификатор — состояние/вариант, через двойной дефис
--; - элементы не вкладываются бесконечно:
block__elem1__elem2— плохо.
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 / right | margin-inline-start / end |
| margin-top / bottom | margin-block-start / end |
| padding-left / right | padding-inline-start / end |
| width / height | inline-size / block-size |
| top / left/right/bottom | inset-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% дают резиновые медиаблоки, которые резервируют место ещё до загрузки картинки.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); }28. Структура CSS-файлов в проекте
Один файл на 3000 строк сложно поддерживать. Раскладывайте стили по смыслу — действует правило «понятно новому человеку за минуту»:
css/
├── base/ /* переменные, сброс, типографика из ;root */
├── layout/ /* header, footer, netki, контейнеры */
├── components/ /* переиспользуемые блоки: buttons, cards */
├── pages/ /* только страницеспецифичные правила */
└── utils/ /* хелперы: .visually-hidden, .text-muted */- в каждом файле — шапка-комментарий с назначением, как в этом уроке;
- селекторы сортируются по специфичности, уровни вложенности — по глубине;
- глобальные переменные (
:root) — отдельный файл, изменяются редко; - переиспользуемые переменные, а не «магические» числа, разбросанные по коду.
/* 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); }Что дальше
Теперь ты знаешь, как устроен CSS: от селекторов и box model до flexbox, grid, анимаций, БЭМ и логических свойств. Попрактикуйся на реальном проекте — свёрстай карточку, кнопку и шапку из примеров выше в браузере, проверьте себя в тестах по HTML и CSS и соберите целую страницу в Практике: лендинг. Углубиться в раскладку и анимации можно в Flexbox и Grid и CSS-анимации.