В CSS-верстке расстояния между элементами часто реализуют через margin. Это приводит к техдолгу: элементы повышают взаимные зависимости, усложняя поддержку и масштабирование. Откажитесь от margin, это музыка дьявола, это она играет в аду! Юзайте только gap. Да, это требует дополнительных оберток, но создает четкие, самодостаточные узлы. Результат: чистый код, предсказуемое поведение, меньше техдолга.

Проблемы margin: антипаттерн и техдолг

Margin — это внешний отступ, который влияет на соседей, нарушая принцип инкапсуляции. В оценке паттернов это антипаттерн: он создает смысловые коллизии. Например, margin-bottom одного элемента диктует расстояние до следующего, но если сосед изменится (добавится/уберется класс), весь layout сломается. Это приводит к "возне" при поддержке: разработчики тратят время на отладку цепных реакций.

Техдолг накапливается: в большом проекте margin размножаются, создавая зависимости. Масштабирование страдает — рефакторинг одного блока рушит соседние. Margin повышает связанность между компонентами. В итоге: хрупкий код, где визуальные группы не отражают семантику, а отступы "держат" всю верстку на хрупких связях.

<!-- Пример: margin создает зависимости -->
<div class="container">
  <div class="item1" style="margin-bottom: 1rem;">Элемент 1</div>
  <div class="item2">Элемент 2</div>
</div>
/* CSS */
.item1 { /* Здесь margin влияет на item2 */ }

Gap как глоток холодненького

Gap — это внутренний отступ контейнера, не выходящий за его границы. В оценке паттернов это SOLID подход: элементы становятся независимыми сущностями. Контейнер управляет расстояниями между детьми, сохраняя инкапсуляцию. Дополнительные узлы (обертки) — не минус, а плюс: они выделяют визуальные и семантические группы, повышая читаемость.

По теханализу, gap снижает связанность (элементы не зависят от соседей). В Flex/Grid это предсказуемо: нет коллапса margin, нет неожиданных сдвигов. Масштабирование упрощается — меняй контейнер, не трогая детей. В долгосрочке: меньше багов, проще рефакторинг, код как модульные блоки.

<!-- Пример: gap в контейнере -->
<div class="container">
  <div class="item1">Элемент 1</div>
  <div class="item2">Элемент 2</div>
</div>
/* CSS */
.container {
  display: flex;
  flex-direction: column;
  gap: 1rem;
}

Простой пример

Рассмотрим контейнер с тремя элементами: два — часть одной группы (кнопки), третий — отдельный (текст). С margin расстояния зависят от элементов; с gap — группируем в обертки.

<!-- Без margin: группируем кнопки -->
<div class="container">
  <div class="buttons-group">
    <button>Кнопка 1</button>
    <button>Кнопка 2</button>
  </div>
  <p>Отдельный текст</p>
</div>
.container {
  display: flex;
  flex-direction: column;
  gap: 1rem; /* Расстояние между группой и текстом */
}

.buttons-group {
  display: flex;
  gap: 0.5rem; /* Внутри группы */
}

Сложный пример

Три узла: блок A (текст + изображение), блок B (список), блок C (форма). Расстояния: 1rem между A и B, 2.5rem между B и C. Margin кажется проще, но это создаст зависимости, что есть антипаттерн, чего мы избегаем. Одним gap не обойтись — нужны обертки для групп (Это не избыточность, это соблюдение паттерна и структуры): объединяем A+B в группу с малым gap, а C — отдельно с большим.

<!-- Дополнительные узлы для сущностей -->
<div class="main-container">
  <div class="group-ab">
    <div class="block-a">
      <p>Текст A</p>
      <img src="img.jpg" alt="Изображение">
    </div>
    <ul class="block-b">
      <li>Пункт 1</li>
      <li>Пункт 2</li>
    </ul>
  </div>
  <form class="block-c">
    <input type="text">
    <button>Отправить</button>
  </form>
</div>
.main-container {
  display: flex;
  flex-direction: column;
  gap: 2.5rem; /* Между AB и C */
}

.group-ab {
  display: flex;
  flex-direction: column;
  gap: 1rem; /* Между A и B */
}

.block-a, .block-b, .block-c {
  /* Стили блоков, без margin */
}

Заключение

Отказ от margin для отступов — не прихоть, а стратегия для устойчивого кода. Антипаттерн margin плодит коллизии и техдолг, нарушая SOLID-принципы в CSS. Gap же строит иерархию целостных сущностей: дополнительные узлы — инвестиция в семантику, упрощающая поддержку и масштабирование. В проектах это снижает время на фиксы, повышает предсказуемость. Gap-центричный подход: верстка станет модульной, как Lego, без хрупких зависимостей

Комментарии (5)


  1. strokoff
    31.08.2025 08:23

    Пару вопросов. Gap не позволяет задавать внешние отступы у контейнера - как вы предлагаете это решать?
    Еще вопрос - не могли бы вы раскрыть все принципы SOLID в CSS? Я просто знаю только border: 1px solid.
    И последний вас не смущает увеличение размера и глубины DOM а также вес самой разметки - только ради избегания margin? Напоминает боязнь у некоторых людей наступать на швы плитки


    1. protonselijah Автор
      31.08.2025 08:23

      1) В этом и суть подхода - без внешних отступов. Все позиционирование дочерних узлов идет через родителя. Если у узла должен быть внешний отступ (например 1.5rem по бокам), то его должен реализовать родительский узел через свой внутренний отступ, через padding

      А в случаях между дочерними узлами, вместо использования margin, создавать доп узел (например div) выделяя тем самым сущность и уже работать с gap

      Это по большей степени сильно роляет, когда реализуешь base компонент (Например Div, Block и тд), и реализация под капотом этого base влияет на весь дальнейший проект

      На местах может и не так критично, когда ты раз за разом пишешь заново стили. Но если ты "автоматизируешь" верстку за счет грамотно написанных базовых компонентов, то кейс с margin может сыграть злую шутку и в дальнейшем придется уже пользоваться знанием весов)))

      2) Это слишком громоздкий вопрос, можешь в любую сетку вбить "Принципы SOLID в CSS"

      3) Нет, тк на рантаймы это особо не влияет. Если имеешь в виду визуальное восприятие размера кода, то обычно все распихано по компонентам, а там и так обычно верстки кот наплакал, поэтому лишний узел не будет усложнять


  1. karrakoliko
    31.08.2025 08:23

    `.specific-block + .very-specific-block { margin-top: 1em;}`


  1. dom1n1k
    31.08.2025 08:23

    Ну в целом так и есть - паразитные связи действительно появляются.
    Кроме того, по многолетним наблюдениям, фронты часто используют марджины как костыли. Когда что-то куда-то уплыло - вместо того, чтобы разобраться что не так, просто фигачат односторонние марджины.

    Совсем запрещать марджин это всё же перебор, но по возможности минимизировать - да.


  1. Alinaki
    31.08.2025 08:23

    Вы когда статьи пишете через гпт, вы хоть картинки отрисовывайте чтоль