В 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, без хрупких зависимостей

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


  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. Maliglood
      31.08.2025 08:23

      Зачем вам внешние отступы у контейнера?


  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

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


  1. frostsumonner
    31.08.2025 08:23

    Если у меня 5 элементов с отступами 1, 2, 3 и 4 rem - сколько доп элементов мне надо создать?


    1. Maliglood
      31.08.2025 08:23

      Вы имеете в виду отступы лесенкой?


  1. K1nGsmaN
    31.08.2025 08:23

    класс, ещё одна «ai-powered» статья.. чатгпт что угодно оправдает, если его попросить.

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

    надо комбинировать подходы и смотреть по ситуации, а не создавать догматы, как «дядя Боб»


  1. dabrahabra
    31.08.2025 08:23

    БЭМ же!


  1. Wintz
    31.08.2025 08:23

    Марджины каждого элемента для того чтобы сделать отступ конкретно для данного элемента, а позиционирование элементов - через родителя. Если вы их неправильно используете - не значит что их придумал дьявол


  1. MyraJKee
    31.08.2025 08:23

    Опа, solid уже и до css дотянулся


  1. bozzhik
    31.08.2025 08:23

    Тут все зависит от того, как использовать. В tailwindcss отлично применяется margin через space-x-* и space-y-*


  1. gun_dose
    31.08.2025 08:23

    Для типографских элементов margin незаменим. Ну или при использовании флекса, к примеру margin-left: auto, чтобы загнать элемент в конец, очень полезная штука.

    А вот настоящий антипаттерн - это засирать вёрстку лишними обёртками ради того, чтобы зачем-то применить принципы программирования в том, что программированием не является.


  1. davidaganov
    31.08.2025 08:23

    во-первых, фронт на то и фронт, нередки случаи когда между 1 и 2 блоком отступ в 20пх, между 2 и 3 - 40пх, а от футера до блока над ним - 150пх. как решать такое гэпами, рушить семантику кучей дивов которые будут просто давать разного размера отступы?

    во-вторых, не знаю, не идеальный метод возможно, но для себя в своих проектах я просто решил, что отступы у блока могут быть только сверху, а не снизу, поэтому каждый блок/секция на сайте имеет margin-top, и сколь угодно перемещай эти блоки, удаляй и переиспользуй - они не слипнутся из-за отступа сверху. единственный минус это когда блок на странице А имеет отступ от верхнего блока 100пх, а на странице Б он стоит первый и слишком большое пространство получается между хедером и ним, но и такое решается во фреймвлрках тем, что отступы задаются не внутри компонента-секции, а снаружи, в пэйдже, например

    <main>
      <Block class="mt-10" />
      <Block class="mt-20" />
    </main>

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


  1. kovaldos
    31.08.2025 08:23

    Заголовок в стиле ленты новостей)

    Интересное мнение. Однако противоречивое как по мне. Лишние обертки ради отступов… ну такое… Одно дело, когда тебе нужен родитель. Тут конечно согласен. При этом всегда можно помнить о принципах однонаправленности верстки. Т.е. не использовать margin-bottom и margin-top одновременно. Ну и всегда можно установить, как я думаю, довольно распространенное в командах правило - не использовать внешние отступы для БЭМ-блоков, ну или для родительских блоков, кому БЭМ не по душе.

    Флекс-гап к тому же все еще не до конца поддерживается на старых сафари для IOS.

    Так что мнение автора вполне имеет место быть, однако как всегда, есть нюансы)

    Спасибо за статью


  1. Pavel_20
    31.08.2025 08:23

    Есть ещё хороший селектор >*:not(:last-child) для добавления марджинов (например на текстовых контентных страницах, где могу идти разные теги без классов)


  1. proll4588
    31.08.2025 08:23

    Участвую в разработке маркетплейса и столкнулись с такой проблемой, gap поддерживается не на всех версиях iOS. Да, таких устройств среди пользователей очень мало, но они есть и их надо поддерживать. И тут либо использовать margin (в списках, которые подразделяют перенос контента, использовать не получится), либо гриды. Но тут уже дело поддержки устройств. А так да, gap маст хэв.


  1. zmiuko
    31.08.2025 08:23

    Псевдоинженерия от gpt