Модуль 05 — Блочная модель

Почему блок шире, чем вы задали, и откуда взялся лишний отступ

Прогресс курса Модуль 5 из 9

Что вы освоите в этом модуле

01

Из чего состоит блок

Каждый элемент на странице — прямоугольник из четырёх слоёв, от центра наружу:

СлойСвойствоЧто это
Содержимоеwidth, heightТекст, картинка, вложенные элементы
Внутренний отступpaddingРасстояние от содержимого до рамки; закрашивается фоном блока
РамкаborderТолщина, стиль, цвет: 1px solid #ddd
Внешний отступmarginРасстояние до соседей; всегда прозрачен

Отступы записывают по сторонам (padding-top, margin-left…) или сокращённо по часовой стрелке от верха: margin: 10px 20px 30px 40px — верх, право, низ, лево; margin: 10px 20px — верх-низ и лево-право; margin: 10px — все стороны.

В инструментах разработчика (F12 → Elements → вкладка Computed) у выбранного элемента нарисована схема этих четырёх слоёв с размерами — первый инструмент, когда «что-то съехало».

02

box-sizing: почему блок шире

По умолчанию width задаёт ширину только содержимого. Отступы и рамка добавляются сверху. Серая полоса в примере — ровно 300px:

<!DOCTYPE html>
<html lang="ru">
<head>
    <meta charset="UTF-8">
    <title>Блочная модель</title>
    <style>
        body { font-family: Arial, sans-serif; }
        .ruler { width: 300px; height: 10px; background: #999; }
        .box {
            width: 300px;
            padding: 20px;
            border: 5px solid #1967d2;
            margin: 10px 0;
            background: #eef3fb;
        }
        .border-box { box-sizing: border-box; }
    </style>
</head>
<body>
    <div class="ruler"></div>
    <div class="box">width: 300px — блок шире линейки</div>
    <div class="box border-box">width: 300px и box-sizing: border-box</div>
</body>
</html>
Результат в браузере
Серая полоса-линейка; под ней голубой блок с синей рамкой, заметно шире линейки; ниже такой же блок шириной ровно с линейку

Первый блок занимает 300 + 2 × 20 + 2 × 5 = 350px. С box-sizing: border-box width означает ширину вместе с отступами и рамкой — блок занимает ровно 300px, а на содержимое остаётся 250px. Так считать проще, поэтому почти каждый файл стилей начинается со строки, включающей это для всех элементов:

*, *::before, *::after { box-sizing: border-box; }
03

Блочные и строчные элементы

Свойство display определяет, как элемент встаёт среди соседей:

displayПоведениеЭлементы по умолчанию
blockС новой строки, на всю ширину родителя; width, height, все отступы работаютdiv, p, h1–h6, ul, section, header
inlineВ строке текста; width и height не действуют, вертикальные margin не раздвигают строкиspan, a, strong, em
inline-blockВ строке, но с размерами и отступами, как у блокаbutton, input, img ведёт себя похоже
noneЭлемент не отображается и не занимает места—
<!DOCTYPE html>
<html lang="ru">
<head>
    <meta charset="UTF-8">
    <title>display</title>
    <style>
        body { font-family: Arial, sans-serif; }
        span, div.b {
            width: 120px;
            padding: 4px;
            margin: 6px;
            border: 2px solid #c62828;
        }
        .ib { display: inline-block; }
    </style>
</head>
<body>
    <div class="b">div — блок</div>
    <div class="b">div — блок</div>
    <p>Текст <span>span — строчный</span> и <span>ещё span</span>: ширина не действует.</p>
    <p>Текст <span class="ib">inline-block</span> и <span class="ib">inline-block</span> — ширина действует.</p>
</body>
</html>
Результат в браузере
Два блока div в рамках во всю ширину друг под другом; в абзаце два span в рамках по размеру текста; в последнем абзаце два элемента inline-block одинаковой ширины 120 пикселей

Ширина 120px сработала у блоков div и у inline-block, но не у обычного span. display меняет только поведение, не смысл: ссылка с display: block остаётся ссылкой. В модулях 06 и 07 появятся ещё два значения — flex и grid.

04

Схлопывание отступов

Вертикальные внешние отступы соседних блоков не складываются, а схлопываются: остаётся больший из двух.

<!DOCTYPE html>
<html lang="ru">
<head>
    <meta charset="UTF-8">
    <title>Схлопывание отступов</title>
    <style>
        body { font-family: Arial, sans-serif; }
        .a, .b { margin: 20px 0; padding: 6px; background: #fff3e0; border: 1px solid #ef6c00; }
    </style>
</head>
<body>
    <div class="a">margin-bottom: 20px</div>
    <div class="b">margin-top: 20px — между блоками 20px, а не 40px</div>
</body>
</html>
Результат в браузере
Два оранжевых блока один под другим, промежуток между ними такой же, как отступ над первым блоком

Так задумано для текста: абзацы с margin: 1em 0 стоят на расстоянии 1em, а не 2em. Горизонтальные отступы не схлопываются никогда. Отступ первого вложенного элемента может «вытечь» наружу родителя — заголовок h1 с верхним отступом сдвигает вниз весь блок, в котором лежит. Лечится padding у родителя или раскладкой flex/grid (у их элементов отступы не схлопываются).

05

Колонка по центру

Классический приём для основной колонки сайта: ограничить ширину max-width и поставить margin слева и справа в auto — браузер поделит свободное место поровну.

<!DOCTYPE html>
<html lang="ru">
<head>
    <meta charset="UTF-8">
    <title>Центрирование</title>
    <style>
        body { font-family: Arial, sans-serif; margin: 0; background: #eceff1; }
        .container {
            max-width: 360px;
            margin: 16px auto;
            padding: 16px;
            background: white;
        }
    </style>
</head>
<body>
    <div class="container">
        Колонка текста шириной не больше 360px по центру окна.
        На узком экране она занимает всю ширину.
    </div>
</body>
</html>
Результат в браузере
В широком окне белая колонка с текстом стоит по центру на сером фоне, по бокам свободное место
Результат в браузере
В узком окне та же колонка занимает всю ширину

max-width вместо width — ключ к адаптивности: на широком экране колонка не шире 360px, на узком сжимается до ширины окна, и горизонтальной прокрутки нет. Длина строки текста для удобного чтения — 60–80 символов, поэтому колонку статьи ограничивают примерно max-width: 70ch (ch — ширина символа «0»).

06

Переполнение

Если задать блоку фиксированную высоту, а содержимое окажется больше, оно вылезет за границы: по умолчанию overflow: visible.

<!DOCTYPE html>
<html lang="ru">
<head>
    <meta charset="UTF-8">
    <title>Переполнение</title>
    <style>
        body { font-family: Arial, sans-serif; }
        .note { width: 260px; height: 32px; border: 2px solid #6a1b9a; margin-bottom: 64px; }
        .scroll { overflow: auto; }
    </style>
</head>
<body>
    <div class="note">Текст длиннее, чем помещается в блок высотой 32px, вылезает за рамку и налезает на соседей.</div>
    <div class="note scroll">С overflow: auto у блока появляется своя прокрутка, и текст остаётся внутри рамки.</div>
</body>
</html>
Результат в браузере
Верхний блок: последняя строка текста вышла за нижнюю фиолетовую рамку; нижний блок: видно только начало текста, остальное обрезано рамкой и прокручивается

overflow: auto — прокрутка, когда нужно; hidden — обрезать. Лучшее решение чаще всего — не задавать height вовсе: блок вырастет по содержимому. Текст на кнопках и в карточках бывает длиннее, чем на макете — переводы, длинные фамилии, крупный шрифт у пользователя, — поэтому верстают с запасом.

07

Карточка целиком

Всё из модуля в одном компоненте: border-box, ограничение ширины, отступы, скругление border-radius, тень box-shadow (смещение по x, по y, размытие, цвет), обнулённые отступы заголовка и абзаца внутри карточки:

<!DOCTYPE html>
<html lang="ru">
<head>
    <meta charset="UTF-8">
    <title>Карточка</title>
    <style>
        *, *::before, *::after { box-sizing: border-box; }
        body { margin: 0; padding: 16px; font-family: Arial, sans-serif; background: #f5f5f5; }
        .card {
            max-width: 320px;
            padding: 16px 20px;
            background: white;
            border: 1px solid #ddd;
            border-radius: 12px;
            box-shadow: 0 2px 6px rgb(0 0 0 / 12%);
        }
        .card h1 { margin: 0 0 8px; font-size: 1.25rem; }
        .card p { margin: 0 0 12px; color: #555; }
        .card .price { font-weight: bold; color: #1967d2; }
    </style>
</head>
<body>
    <article class="card">
        <h1>Раф с лавандой</h1>
        <p>Эспрессо, сливки и лавандовый сироп.</p>
        <span class="price">290 ₽</span>
    </article>
</body>
</html>
Результат в браузере
Белая карточка со скруглёнными углами и мягкой тенью на сером фоне: заголовок «Раф с лавандой», описание серым, цена синим жирным

Начало файла стилей

  • *, *::before, *::after { box-sizing: border-box; }
  • body { margin: 0; } — у body по умолчанию отступ 8px.
  • img { max-width: 100%; height: auto; } — картинка не шире своего блока.
  • Шрифт, цвет текста и межстрочный интервал (line-height: 1.5) — у body.

Ключевые выводы модуля

Запомните главное

  • Блок = содержимое + padding + border + margin
  • box-sizing: border-box — width включает отступы и рамку; ставят всем элементам
  • block — на всю ширину, inline — без размеров, inline-block — в строке с размерами
  • Вертикальные margin соседей схлопываются до большего
  • Колонка по центру — max-width + margin: 0 auto
  • Фиксированная height — источник переполнения; пусть блок растёт по содержимому
Практические задания — на учебном портале. Задания, критерии оценивания, сдача работ и оценки преподавателя — в курсе на portal.nevabit.ru. Учётную запись выдаёт преподаватель.
Модуль 04: CSS Все модули Модуль 06: Flexbox