В 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)

dom1n1k
31.08.2025 08:23Ну в целом так и есть - паразитные связи действительно появляются.
Кроме того, по многолетним наблюдениям, фронты часто используют марджины как костыли. Когда что-то куда-то уплыло - вместо того, чтобы разобраться что не так, просто фигачат односторонние марджины.Совсем запрещать марджин это всё же перебор, но по возможности минимизировать - да.

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

K1nGsmaN
31.08.2025 08:23класс, ещё одна «ai-powered» статья.. чатгпт что угодно оправдает, если его попросить.
идея бредовая. полностью от маржинлв отказаться нельзя. вы просто меняете один костыль на другой. с одной стороны нежелательные связи между блоками, с другой куча мусорных оберток.
надо комбинировать подходы и смотреть по ситуации, а не создавать догматы, как «дядя Боб»

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

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

gun_dose
31.08.2025 08:23Для типографских элементов margin незаменим. Ну или при использовании флекса, к примеру margin-left: auto, чтобы загнать элемент в конец, очень полезная штука.
А вот настоящий антипаттерн - это засирать вёрстку лишними обёртками ради того, чтобы зачем-то применить принципы программирования в том, что программированием не является.

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>в таком случае никакие марджины проблем не создают, хоть минусовыми их делай, не развалишь. а чатгпт респект, статьи с каждым разом все правдоподобнее и правдоподобнее, почти на настоящую тянет

kovaldos
31.08.2025 08:23Заголовок в стиле ленты новостей)
Интересное мнение. Однако противоречивое как по мне. Лишние обертки ради отступов… ну такое… Одно дело, когда тебе нужен родитель. Тут конечно согласен. При этом всегда можно помнить о принципах однонаправленности верстки. Т.е. не использовать margin-bottom и margin-top одновременно. Ну и всегда можно установить, как я думаю, довольно распространенное в командах правило - не использовать внешние отступы для БЭМ-блоков, ну или для родительских блоков, кому БЭМ не по душе.
Флекс-гап к тому же все еще не до конца поддерживается на старых сафари для IOS.
Так что мнение автора вполне имеет место быть, однако как всегда, есть нюансы)
Спасибо за статью

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

proll4588
31.08.2025 08:23Участвую в разработке маркетплейса и столкнулись с такой проблемой, gap поддерживается не на всех версиях iOS. Да, таких устройств среди пользователей очень мало, но они есть и их надо поддерживать. И тут либо использовать margin (в списках, которые подразделяют перенос контента, использовать не получится), либо гриды. Но тут уже дело поддержки устройств. А так да, gap маст хэв.
strokoff
Пару вопросов. Gap не позволяет задавать внешние отступы у контейнера - как вы предлагаете это решать?
Еще вопрос - не могли бы вы раскрыть все принципы SOLID в CSS? Я просто знаю только border: 1px solid.
И последний вас не смущает увеличение размера и глубины DOM а также вес самой разметки - только ради избегания margin? Напоминает боязнь у некоторых людей наступать на швы плитки
protonselijah Автор
1) В этом и суть подхода - без внешних отступов. Все позиционирование дочерних узлов идет через родителя. Если у узла должен быть внешний отступ (например 1.5rem по бокам), то его должен реализовать родительский узел через свой внутренний отступ, через padding
А в случаях между дочерними узлами, вместо использования margin, создавать доп узел (например div) выделяя тем самым сущность и уже работать с gap
Это по большей степени сильно роляет, когда реализуешь base компонент (Например Div, Block и тд), и реализация под капотом этого base влияет на весь дальнейший проект
На местах может и не так критично, когда ты раз за разом пишешь заново стили. Но если ты "автоматизируешь" верстку за счет грамотно написанных базовых компонентов, то кейс с margin может сыграть злую шутку и в дальнейшем придется уже пользоваться знанием весов)))
2) Это слишком громоздкий вопрос, можешь в любую сетку вбить "Принципы SOLID в CSS"
3) Нет, тк на рантаймы это особо не влияет. Если имеешь в виду визуальное восприятие размера кода, то обычно все распихано по компонентам, а там и так обычно верстки кот наплакал, поэтому лишний узел не будет усложнять
Maliglood
Зачем вам внешние отступы у контейнера?