Читаем CSS
селекторы, каскад, раскладка
Что это
CSS отвечает на два вопроса: к чему применить (селектор) и что сделать (свойства). Сложность не в свойствах — их просто много и их гуглят. Сложность в двух других местах: почему правило не применилось и почему блок стоит не там.
Обе темы разбираются ниже, и обе — на настоящих снимках того, что нарисовал браузер.
Как выглядит в коде
.card {
display: flex;
gap: 8px;
padding: 12px;
border: 1px solid #d8dce5;
}
.card__title {
font-size: 18px;
font-weight: 600;
}
.card:hover { background: #f7f8fa; }Селекторы
| Селектор | К чему применится |
|---|---|
.card | элементы с классом card |
#main | элемент с id="main" |
article | все теги <article> |
.card .title | .title внутри .card |
.card > .title | .title — прямой потомок |
.card:hover | .card под курсором |
[data-city="oslo"] | по значению атрибута |
Пробел между классами значит «внутри», и это самый частый источник
недоумения: .card .title и .card.title — разные вещи. Второе —
элемент, у которого оба класса сразу.
Каскад: кто побеждает
Когда к элементу подходят два правила, выигрывает более «весомое». Порядок по возрастанию веса:
| Что | Вес |
|---|---|
тег: article | низкий |
класс: .card, :hover, [data-*] | средний |
id: #main | высокий |
style="..." прямо в теге | очень высокий |
!important | перебивает всё |
При равном весе выигрывает тот, что ниже в файле.
Отсюда практическое следствие: !important в сгенерированном CSS — почти
всегда признак того, что ИИ не разобрался, какое правило мешает, и
перебил его силой. Работать будет; следующая правка станет труднее.
Раскладка: display решает всё
Одна и та же разметка из трёх блоков, три значения display:

display. Снимок настоящий — так это нарисовал браузер.block— каждый элемент на своей строке, во всю доступную ширину. Так ведут себяdiv,p,h1по умолчанию.flex— дети выстраиваются в ряд по содержимому. Для рядов кнопок, карточек, панелей.grid— дети раскладываются по заданной сетке колонок.
Девяносто процентов современной раскладки — это flex и grid. Если в
сгенерированном CSS встречаются float или position: absolute для
расстановки блоков, это устаревший подход (статья 3.1, причина 3).
Коробка: откуда берётся ширина
Самая частая неожиданность в CSS. Два блока, у обоих width: 200px,
padding: 20px, border: 4px:

content-box блок шире заданного на отступы и рамку.Измерено в браузере:
content-box: 248px
border-box: 200pxПри box-sizing: content-box (поведение по умолчанию) width задаёт ширину
содержимого, а отступы и рамка добавляются сверху: 200 + 20·2 + 4·2 = 248.
При border-box — width задаёт ширину всего блока целиком.
Поэтому почти в каждом проекте первой строкой стоит:
* { box-sizing: border-box; }Как сказать ИИ
Почему это правило не применяется к .card__title?
Какой селектор его перебивает? Код не меняй, объясни.Разложи эти карточки в три колонки с промежутком 16 пикселей,
на узком экране — в одну. Используй grid, без float
и position: absolute.В этом CSS есть !important. Разберись, какое правило мешало,
и перепиши без него.На что смотреть
!important. Признак перебитого конфликта, а не решения.
Магические числа. margin-top: 37px, width: 433px — подогнано на глаз
под один экран и развалится на другом.
position: absolute для раскладки. Элемент выпадает из потока, соседи его
не видят, на другом размере экрана всё съедет.
Фиксированная высота у текстового блока. height: 40px на элементе с
текстом: при другом шрифте или длинном слове текст обрежется.
Повторяющиеся значения. Один и тот же отступ, вписанный в десяти местах.
В современном CSS для этого есть переменные: var(--gap).
Стили «на всякий случай». float: left рядом с display: flex — одно
из двух не работает, и непонятно какое.
Шпаргалка
Селектор отвечает «к чему», свойства — «что сделать».
Пробел в селекторе значит «внутри»:
.a .b≠.a.b.Вес: тег < класс < id <
style<!important; при равенстве — что ниже.!importantв коде от ИИ — перебитый конфликт, а не решение.Раскладка сегодня —
flexиgrid;floatустарел.Блок шире, чем задал? Проверь
box-sizing.