Веб-разработка
CSS: от каскада до Grid
Цели урока
- Понимать алгоритм специфичности и каскада CSS
- Строить одномерные раскладки на Flexbox с flex-grow/shrink/basis
- Создавать двумерные layouts на CSS Grid с named areas и auto-fill
- Применять mobile-first подход, clamp() и Container Queries
Предварительные знания
HTML без CSS - это газета 1995 года: чёрный текст на белом фоне, Times New Roman, никакой структуры. CSS превращает скелет в интерфейс. Но CSS коварен: два правила конфликтуют и непонятно почему, элемент не центрируется, layout рассыпается на мобильном. GitHub в 2020 переписал свои стили и сократил объём CSS на 30% - именно потому что понимание каскада и Grid превратило хаос в систему.
- **GitHub** перешёл на CSS Grid для layout в 2020 году, сократив CSS-код на 30% и устранив баги с вложенными Flexbox
- **Every Layout** (проект Heydon Pickering) показал, что 90% layouts строится из 7 CSS-паттернов без media queries
- **Container Queries** позволяют Shopify создавать виджеты, которые автоматически адаптируются к любому сайту клиента
CSS: от таблиц до Grid
До 1996 года веб-разработчики верстали layout через HTML-таблицы - это был единственный способ создать колонки. CSS 1.0 (1996) принёс базовое форматирование текста, но не решил проблему layout. Десятилетие продолжалась эпоха float-верстки - колонки на основе float с clearfix-хаками. Flexbox появился в 2012 году и вошёл во все браузеры к 2015. CSS Grid - в 2017. До него единственным нативным решением для двумерных layouts были либо таблицы, либо нагромождения Flexbox. Container Queries - последняя революция, 2023 год: компоненты наконец могут адаптироваться к своему контейнеру, а не к окну браузера.
Селекторы и специфичность
**GitHub в 2020 году мигрировал с Sass на нативный CSS - и сократил кодовую базу стилей на 30%.** Причина: война специфичностей разрослась до состояния, когда никто не понимал, почему один стиль перебивает другой. CSS работает по принципу «найти элемент - применить стиль», и когда два правила конфликтуют - побеждает тот, у кого выше **специфичность** (specificity).
| Тип | Пример | Специфичность |
|---|---|---|
| inline style | style="color: red" | 1,0,0,0 |
| #id | #header | 0,1,0,0 |
| .class, [attr], :pseudo-class | .nav, [type="text"], :hover | 0,0,1,0 |
| element, ::pseudo-element | div, p, ::before | 0,0,0,1 |
| * (универсальный) | * | 0,0,0,0 |
**Каскад** - алгоритм разрешения конфликтов. Приоритет (от высшего к низшему): 1) `!important` 2) inline styles 3) специфичность селектора 4) порядок в файле (позднее правило побеждает). **!important - крайняя мера.** Каждый `!important` создаёт долг, который придётся «перебивать» другим `!important`.
**BEM (Block Element Modifier)** - методология именования CSS-классов, которая решает проблему конфликтов без повышения специфичности. Все селекторы - классы одного уровня, коллизий нет.
**CSS Custom Properties** наследуются по DOM-дереву и изменяются через JavaScript: `element.style.setProperty('--color-primary', '#ff0000')`. В отличие от переменных Sass, они работают в runtime - идеально для тем и динамической стилизации.
У элемента <p class="text" id="intro"> есть два правила: `.text { color: blue; }` и `p { color: red; }`. Какой цвет будет у текста?
Flexbox: одномерные раскладки
**До Flexbox вертикальное центрирование было мемом веб-разработки.** Решение через `transform: translateY(-50%)` или `display: table-cell` - это были реальные продакшн-хаки. Flexbox решил это и сотни других задач одной строкой. Ключевое слово: **одномерный** - работает либо по горизонтали, либо по вертикали.
**Две оси Flexbox:** главная (main axis) определяется `flex-direction` - по умолчанию горизонтальная (`row`). Поперечная (cross axis) - перпендикулярна. `justify-content` управляет главной осью, `align-items` - поперечной.
| Свойство | Значения | Что делает |
|---|---|---|
| flex-direction | row | column | row-reverse | column-reverse | Направление главной оси |
| justify-content | flex-start | center | flex-end | space-between | space-around | space-evenly | Распределение по главной оси |
| align-items | flex-start | center | flex-end | stretch | baseline | Выравнивание по поперечной оси |
| flex-wrap | nowrap | wrap | wrap-reverse | Перенос элементов на новую строку |
| gap | 10px | 1rem | Отступы между flex-элементами |
| flex | grow shrink basis (например, 1 0 200px) | Как элемент растягивается/сжимается |
**`flex: 1 1 300px`** - самый полезный паттерн Flexbox. Элемент занимает минимум 300px, растёт при наличии свободного места и переносится при нехватке. Responsive-карточки без единого media query.
Что означает запись `flex: 1 0 200px` на flex-элементе?
CSS Grid: двумерные раскладки
**Flexbox - одномерный: строка ИЛИ колонка. Grid - двумерный: строки И колонки одновременно.** Dashboard, каталог, лэндинг с несколькими секциями - задачи для Grid. Это как таблица, но без ограничений `<table>`, без вложенных div-ов и без войны с вертикальным центрированием.
**`fr` (fraction unit)** - единица, уникальная для Grid. `1fr` означает «одна доля свободного пространства». `grid-template-columns: 1fr 2fr` - вторая колонка в два раза шире первой. `fr` - это как `flex-grow`, но для Grid.
**`grid-template-areas`** - самая наглядная фича Grid. Layout буквально «рисуется» текстом. Каждая строка в кавычках - ряд. Одинаковые имена объединяют ячейки. Точка (`.`) означает пустую ячейку.
| Задача | Flexbox | Grid |
|---|---|---|
| Навигация (горизонт.) | Идеально | Избыточно |
| Центрирование элемента | Подходит | Подходит |
| Dashboard с sidebar | Костыли | Идеально |
| Карточки в ряд | Хорошо с wrap | Хорошо с auto-fill |
| Перекрытие элементов | Невозможно | grid-row/column + z-index |
| Произвольный 2D-макет | Невозможно | Идеально |
**Flexbox и Grid не конкуренты - они дополняют друг друга.** Grid для макета страницы (header/sidebar/content/footer), Flexbox для компонентов внутри (nav links, card content, button group). Grid-контейнер часто содержит Flex-контейнеры.
Что делает `grid-template-columns: repeat(auto-fill, minmax(250px, 1fr))`?
Responsive Design
**60% мирового веб-трафика приходится на мобильные устройства.** Сайт, отлично выглядящий на 27-дюймовом мониторе, может быть непригодным на телефоне. Responsive design - подход, при котором один HTML-документ адаптируется к любому размеру экрана без дублирования контента.
**Mobile-first** означает: базовые стили - для самого маленького экрана, затем через `@media (min-width)` добавляются улучшения. Почему не desktop-first? Проще добавлять сложность, чем убирать. Мобильный layout (одна колонка) - естественное состояние HTML.
**Container Queries (2023)** - революция в responsive design. Media queries реагируют на размер *viewport* (всего окна). Container queries - на размер *родительского контейнера*. Компонент адаптируется независимо от того, где он размещён на странице.
| Технология | Реагирует на | Когда использовать |
|---|---|---|
| Media queries | Размер viewport (окна) | Глобальный layout: columns, navigation |
| Container queries | Размер родителя | Компоненты: cards, widgets |
| clamp() | Размер viewport (плавно) | Typography, spacing - без breakpoints |
| auto-fill / auto-fit | Свободное место в Grid | Сетки карточек, каталоги |
| flex-wrap | Свободное место в Flex | Навигация, группы кнопок |
**Не забывайте про `<meta name="viewport">`** в `<head>`. Без него мобильный браузер рендерит страницу как десктопную (шириной 980px) и масштабирует. Все media queries перестают работать как ожидается.
Responsive design - это добавить несколько media queries с breakpoints для популярных устройств (320px, 768px, 1024px)
Responsive design - это подход, включающий fluid grids, flexible images, современные CSS-функции (clamp, min, max), container queries и media queries. Breakpoints ставятся там, где ломается дизайн, а не под конкретные устройства
Устройств тысячи, и их размеры не укладываются в 3-4 breakpoint. Fluid typography через clamp(), auto-fill Grid и container queries адаптируются к любому размеру без breakpoints вообще. Media queries - один инструмент из многих, а не синоним responsive design
Чем Container Queries отличаются от Media Queries?
Ключевые идеи
- **Специфичность решает конфликты:** inline > #id > .class > element. BEM и Custom Properties помогают избежать войны специфичностей
- **Flexbox - одномерный:** строка или колонка. `justify-content` для главной оси, `align-items` для поперечной. `flex: 1 1 300px` - универсальная адаптивная карточка
- **Grid - двумерный:** строки и колонки одновременно. `grid-template-areas` для сложных layouts, `auto-fill + minmax` для адаптивных сеток
- **Responsive = подход, не media queries.** Mobile-first, clamp() для fluid typography, container queries для компонентов, auto-fill для сеток
Связанные темы
CSS стилизует HTML и взаимодействует с JavaScript:
- HTML и семантическая вёрстка — CSS-селекторы работают с HTML-элементами и их атрибутами
- JavaScript: основы языка — JavaScript динамически меняет CSS через style, classList и Custom Properties
Вопросы для размышления
- Откройте DevTools на любом сайте, найдите элемент и посмотрите вкладку Computed - сколько CSS-правил конкурируют за одно свойство?
- Попробуйте построить layout любимого сайта, используя только Grid и grid-template-areas. Насколько это проще, чем кажется?
- Сузьте окно браузера до 320px. Какие сайты адаптируются плавно (fluid), а какие «прыгают» между breakpoints?
Связанные уроки
- web-01 — HTML и семантика - основа для CSS-селекторов и BEM
- web-03 — JavaScript динамически меняет CSS через classList и Custom Properties
- web-04 — React и компонентная архитектура: CSS Modules и styled-components строятся на принципах специфичности
- gd-02 — Выбор CSS layout (Flexbox vs Grid) аналогичен выбору архитектуры движка - разные инструменты для разных задач
- mob-02 — Responsive design и mobile-first - прямо связаны с lifecycle мобильных приложений
- se-01 — BEM и CSS Custom Properties реализуют принципы SOLID в стилизации
- comp-01-intro