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

Блочные элементы занимают всю доступную ширину и начинаются с новой строки. Строчные -- занимают только ширину своего содержимого и не разрывают строку.

Зачем нужно

Понимание блочной и строчной модели -- основа для работы с layout. От типа элемента зависит, как он ведёт себя в потоке документа: где переносится, какие размеры принимает, как реагирует на margin/padding.

Где используется

  • Верстка любого HTML-документа
  • Понимание CSS display
  • Решение проблем с layout (элементы не встают в ряд, отступы не работают)

Предпосылки

Блочные элементы (block)

Блочный элемент:

  • Начинается с новой строки
  • Занимает 100% ширины родителя
  • Можно задать width, height, margin, padding со всех сторон
  • Может содержать другие блочные и строчные элементы
<!-- Каждый блочный элемент -- на новой строке -->
<div>Первый div (блочный)</div>
<div>Второй div (блочный)</div>
<p>Параграф (блочный)</p>
<h1>Заголовок (блочный)</h1>

Результат:

|Первый div (блочный)                    |
|Второй div (блочный)                    |
|Параграф (блочный)                      |
|Заголовок (блочный)                     |

Список блочных элементов

Элемент Назначение
<div> Универсальный контейнер
<p> Параграф
<h1>...<h6> Заголовки
<ul>, <ol>, <li> Списки
<table> Таблица
<form> Форма
<header>, <footer>, <main> Семантические секции
<section>, <article>, <aside> Семантические секции
<nav> Навигация
<blockquote> Блочная цитата
<pre> Предформатированный текст
<hr> Горизонтальная линия
<figure>, <figcaption> Иллюстрация с подписью
<details>, <summary> Раскрываемый блок
<dialog> Диалоговое окно

Строчные элементы (inline)

Строчный элемент:

  • Не начинается с новой строки
  • Занимает только ширину своего содержимого
  • width и height игнорируются
  • Вертикальные margin игнорируются
  • Вертикальные padding визуально работают, но не отодвигают соседей
<p>
  Это <strong>жирный</strong> текст и <em>курсив</em>,
  а вот <a href="#">ссылка</a> и <span>span</span>.
</p>

Результат:

Это жирный текст и курсив, а вот ссылка и span.

Все строчные элементы остались в одной строке.

Список строчных элементов

Элемент Назначение
<span> Универсальный строчный контейнер
<a> Ссылка
<strong> Важный текст (жирный)
<em> Акцент (курсив)
<b> Визуально жирный (без семантики важности)
<i> Визуально курсивный (технический термин, иностранное слово)
<code> Код
<kbd> Ввод с клавиатуры
<mark> Выделение
<small> Мелкий текст (копирайт, примечания)
<sub>, <sup> Подстрочный / надстрочный
<br> Перенос строки
<wbr> Возможное место переноса
<abbr> Аббревиатура
<time> Дата/время
<img> Изображение (inline-replaced)
<input> Поле ввода (inline-replaced)
<button> Кнопка (inline-replaced)
<label> Метка формы
<select>, <textarea> Элементы форм

Inline-block

inline-block -- гибрид: элемент остаётся в строке, но принимает width, height и вертикальные margin/padding.

<style>
  .badge {
    display: inline-block;
    width: 100px;
    height: 30px;
    line-height: 30px;
    text-align: center;
    background: #e0e0e0;
    border-radius: 4px;
    margin: 4px;
  }
</style>

<span class="badge">HTML</span>
<span class="badge">CSS</span>
<span class="badge">JS</span>

Результат: три бейджа в ряд, каждый с фиксированными размерами.

Сравнение block, inline, inline-block

<style>
  .block {
    display: block;
    width: 200px;
    height: 50px;
    margin: 10px;
    padding: 10px;
    background: lightblue;
  }
  .inline {
    display: inline;
    width: 200px;      /* ИГНОРИРУЕТСЯ */
    height: 50px;      /* ИГНОРИРУЕТСЯ */
    margin: 10px;      /* Вертикальный ИГНОРИРУЕТСЯ */
    padding: 10px;     /* Вертикальный визуально работает, но не отодвигает */
    background: lightgreen;
  }
  .inline-block {
    display: inline-block;
    width: 200px;      /* Работает */
    height: 50px;      /* Работает */
    margin: 10px;      /* Работает полностью */
    padding: 10px;     /* Работает полностью */
    background: lightyellow;
  }
</style>

<div class="block">Block</div>
<span class="inline">Inline</span>
<span class="inline">Inline</span>
<br><br>
<span class="inline-block">Inline-block</span>
<span class="inline-block">Inline-block</span>
Свойство block inline inline-block
Новая строка Да Нет Нет
width/height Работает Игнорируется Работает
margin (верт.) Работает Игнорируется Работает
margin (гориз.) Работает Работает Работает
padding (верт.) Работает Визуально да, не отодвигает Работает
Содержит block Да Нет* Да

*Исключение: <a> может содержать блочные элементы в HTML5.

Поток документа (document flow)

Нормальный поток -- как браузер размещает элементы без CSS-позиционирования:

+--------------------------------------------------+
| <header>                              (block)     |
+--------------------------------------------------+
| <nav>                                 (block)     |
+--------------------------------------------------+
| <main>                                (block)     |
|   <h1>Заголовок</h1>                 (block)     |
|   <p>                                 (block)     |
|     Текст <a>ссылка</a> ещё текст    (inline)    |
|     <strong>важное</strong>           (inline)    |
|   </p>                                            |
|   <p>Другой параграф</p>             (block)     |
| </main>                                           |
+--------------------------------------------------+
| <footer>                              (block)     |
+--------------------------------------------------+

Блочные элементы укладываются вертикально (сверху вниз). Строчные -- горизонтально (слева направо, с переносом).

Изменение поведения через CSS display

Любой элемент можно "переключить":

<style>
  /* Строчный элемент ведёт себя как блочный */
  .block-link {
    display: block;
    padding: 10px;
    background: #f0f0f0;
  }

  /* Блочный элемент ведёт себя как строчный */
  .inline-heading {
    display: inline;
  }

  /* Список горизонтально */
  .horizontal-list li {
    display: inline-block;
    margin-right: 10px;
  }
</style>

<a href="#" class="block-link">Ссылка во всю ширину</a>

<h2 class="inline-heading">Заголовок</h2>
<h2 class="inline-heading">рядом</h2>

<ul class="horizontal-list">
  <li>Пункт 1</li>
  <li>Пункт 2</li>
  <li>Пункт 3</li>
</ul>

Современные значения display

/* Основные */
display: block;
display: inline;
display: inline-block;
display: none;          /* Убирает из потока */

/* Флексбокс */
display: flex;          /* Блочный flex-контейнер */
display: inline-flex;   /* Строчный flex-контейнер */

/* Грид */
display: grid;          /* Блочный grid-контейнер */
display: inline-grid;   /* Строчный grid-контейнер */

/* Другие */
display: contents;      /* Убирает обёртку, дети в потоке родителя */
display: flow-root;     /* Создаёт новый BFC (block formatting context) */

Правила вложенности

<!-- МОЖНО: блочный в блочном -->
<div>
  <p>Параграф</p>
</div>

<!-- МОЖНО: строчный в блочном -->
<p>Текст <strong>жирный</strong></p>

<!-- МОЖНО (HTML5): блочный в <a> -->
<a href="/article">
  <article>
    <h2>Заголовок</h2>
    <p>Описание</p>
  </article>
</a>

<!-- НЕЛЬЗЯ: блочный в строчном (кроме <a>) -->
<!-- Невалидно: -->
<span>
  <div>Блок внутри span</div>
</span>

<!-- НЕЛЬЗЯ: <p> в <p> -->
<!-- Браузер автоматически закроет первый <p> -->
<p>Первый <p>Второй</p>
<!-- Станет: <p>Первый</p><p>Второй</p> -->

Частые ошибки

Ошибка Почему плохо Как правильно
width на inline-элементе Игнорируется Переключи на inline-block или block
Вертикальный margin на inline Не работает Используй inline-block
<div> внутри <span> Невалидная вложенность Блочный -- только в блочном
<p> внутри <p> Браузер принудительно закроет первый Используй <div> или <section>
Пробелы между inline-block Нежелательные зазоры между элементами font-size: 0 на родителе или flex
Забывают про replaced elements <img>, <input> -- inline, но принимают размеры Это inline-replaced, особая категория

Практика

  1. Создай три <div> и три <span> -- увидь разницу в поведении
  2. Попробуй задать width: 200px для <span> -- убедись, что не работает
  3. Переключи <span> на display: inline-block и повтори
  4. Создай горизонтальное меню из <ul> с li { display: inline-block; }
  5. Попробуй вложить <div> в <span> -- проверь валидатором

Связанные темы

Ресурсы