Программирование с ИИ
ENRU
8.3

Читаем 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. Снимок настоящий — так это нарисовал браузер.
Одна и та же разметка при разных 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 блок шире заданного на отступы и рамку.

Измерено в браузере:

измерено
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.