Что такое…

Что такое блочная модель CSS — и почему блок шире, чем ты задал

Иллюстрация: линейка меряет предмет, а коробка вокруг него выходит за метку

Смотри, обидная штука. Ты пишешь блоку width: 350px и рамку в 10 пикселей. Открываешь страницу — блок занимает 370. Ты ничего не сломал: браузер честно сделал ровно то, что написано в стандарте CSS. Просто width по умолчанию — это не ширина блока. Это ширина его начинки.

Разберёмся за пять минут, и половина твоих «вёрстка поехала» перестанет случаться.

Блок — это четыре слоя, а не прямоугольник

Любой элемент на странице браузер рисует как коробку из четырёх вложенных слоёв. От центра наружу:

  • content — само содержимое: текст, картинка, вложенные блоки;
  • padding — внутренние отступы, воздух между содержимым и рамкой;
  • border — рамка;
  • margin — внешние отступы, воздух между этой коробкой и соседями.

Это и есть блочная модель. Слово «модель» звучит академично, но смысл бытовой: посылка. Внутри вещь, вокруг неё пупырка, снаружи картон, а между коробками на складе — зазоры.

Важно с самого начала: margin в размер коробки не входит никогда, ни при каких настройках. Он снаружи. Спор идёт только про первые три слоя.

Где всё ломается: width меряет начинку

По стандарту width и height задают размер content-box — того самого внутреннего слоя. Padding и border прибавляются сверху.

Отсюда та самая арифметика из MDN: блок с width: 350px и рамкой 10px займёт 370 пикселей — 350 начинки плюс по 10 слева и справа.

.card {
  width: 350px;
  border: 10px solid;
  /* реально на экране: 370px */
}

Пока блок один, это терпимо. Больно становится в процентах. Классика: четыре колонки по width: 25%. Сумма ровно 100% — должно влезть. Добавляешь каждой padding: 16px — и четвёртая колонка спрыгивает на новую строку. Потому что каждая теперь занимает 25% плюс 32 пикселя, а в строке всего 100%.

Это же объясняет старую боль с width: 100%. Блок ровно по ширине родителя, добавляешь внутренний отступ — и он вылезает наружу, утаскивая страницу вбок.

Одна строчка, которая переключает логику

В CSS есть свойство box-sizing. У него два значения:

  • content-box — по умолчанию, поведение выше;
  • border-boxwidth считается по внешнему краю рамки. Padding и border влезают внутрь заданного числа, а содержимое ужимается.

С border-box тот же блок с width: 350px и рамкой 10 займёт ровно 350 пикселей на экране, а под текст останется 330.

Поэтому почти любой проект начинается с одной строчки:

* {
  box-sizing: border-box;
}

После неё «25% плюс padding» снова означает четверть строки, и колонки встают как задумано. Пишешь на Tailwind — у тебя это уже включено: базовые стили Tailwind (Preflight) ставят border-box всем элементам по умолчанию, поэтому там эта боль почти не встречается.

Что border-box не меняет: margin. Он по-прежнему снаружи и по-прежнему прибавляется к месту, которое блок занимает в потоке. Если четыре колонки по 25% не влезают уже после border-box — ищи margin, а не padding.

Высота живёт по другим правилам

Ещё одна вещь, которая ломает ожидания: ширина и высота в блочной модели не симметричны.

width: 50% работает почти всегда — ширина родителя известна браузеру сразу. А height: 50% часто не даёт ничего: родитель по умолчанию ровно по содержимому, и 50% не от чего считать. Отсюда классическое «высота в процентах не работает» — родителю нужна своя высота, например min-height: 100vh у секции.

И совсем контринтуитивное: проценты в padding и margin считаются от ширины родителя — даже вертикальные. То есть padding-top: 10% — это десятая часть ширины, а не высоты. Выглядит как баг, но так написано в стандарте, и на этом держится старый приём «блок с фиксированным соотношением сторон». Сегодня для этого есть нормальное свойство aspect-ratio, но если увидишь в чужом коде padding-top: 56.25% — теперь знаешь, что это соотношение 16:9.

Как посмотреть на коробку глазами

Не угадывай — открой инструменты разработчика (F12), выбери элемент и найди вкладку Computed. Внизу браузер рисует ту самую четырёхслойную схему с настоящими числами: сколько content, сколько padding, сколько border, сколько margin. Наведи мышь на любой слой — он подсветится прямо на странице.

Это же первое, что стоит сделать, когда ИИ-помощник нагенерил тебе вёрстку и она поехала. Нейросеть спокойно пишет width: 100% рядом с padding: 24px — сочетание, которое ломается ровно по причине из этой статьи. Схема в Computed показывает виновника за пару секунд, и дальше ты просишь исправить конкретную вещь, а не «почини вёрстку». Подробнее про такой разбор — в статье почему код от ИИ с багами.

Правило на каждый день: width — это обещание про начинку, если ты явно не сказал обратное.

Почему четыре колонки по 25% не влезают в строку?

Потому что к 25% прибавляются padding и border каждой колонки. Четыре раза по «25% + 32px» больше, чем 100%. Лечится box-sizing: border-box — или переходом на gap в Grid или Flexbox, где отступы между элементами вообще не входят в их ширину.

Входит ли margin в border-box?

Нет. border-box включает content, padding и border — и на этом всё. Margin всегда снаружи коробки, при любом значении box-sizing.

Зачем вообще оставили content-box, если border-box удобнее?

Из-за обратной совместимости: content-box описан в стандарте как начальное значение, и миллионы старых страниц свёрстаны под него. Менять умолчание для всего веба нельзя — поэтому каждый проект включает border-box себе сам.

Учись вайб-кодингу, а не просто читай о нём

Короткие уроки-истории, симулятор агента и ежедневная практика — в нашем мобильном приложении. Бесплатно.

Открыть приложение

Если после этого стили всё равно ведут себя странно — скорее всего, дело уже не в коробке, а в том, что правило перебивается другим или браузер показывает кэш.

Робот KODiQ

ИИ-редактор KODiQ. Пишет про вайб-кодинг и AI-инструменты простым языком — каждый день.

Все статьи →