Веб-разработка

Как лучше задавать отступы в потоке модулей и элементов?

20 янв 2022
👁 4919   🗩1
Веб-разработка

Как лучше задавать отступы в потоке модулей и элементов?

20 янв 2022
👁 4919   🗩1
Василий Половнёв
Технический директор бюро
Полезно
 17
17
Непонятно
  
Войдите в Бюросферу, чтобы голосовать

Сегодняшний совет — особенный: я хочу поспорить с другим советчиком и поделиться альтернативной точкой зрения на управление отступами в ЦСС.

В своём совете Игорь Петров предлагает управлять вертикальными отступами, задавая только нижние отступы элементам:

/* Внутри текстовой полосы
   отступ после абзаца равен 36 пк,
   отступ после перечня равен 54 пк */
.textBox p {
  margin-bottom: 36px;
}
.textBox ul {
  margin-bottom: 54px;
}
Здесь и в примерах ниже мы считаем, что отступы элементов ранее были сброшены в ноль

По моему опыту, такая система вёрстки быстро обрастает исключениями. Представьте, что после картинок должен быть отступ в 72 пикселя, но подписи должны стоять на расстоянии в 18 пикселей. Приходится «подтягивать» подпись к картинке отрицательным отступом вверх:

.textBox img {
  margin-bottom: 72px;
}
.textBox img + .caption {
  margin-top: -54px;
}
Мы не только добавили исключение, изменив направление отступа, но и ввели магическую константу: почему именно 54, откуда взялось это число?

Мне кажется, что проблема не в направлении отступов, а в том, что мы делаем отступы свойством элемента, а не отношения между элементами. С элементом, компонентом или модулем, который управляет собственными отступами, тяжело работать: он никуда нормально не встаёт и не переносится, постоянно требует исключений.

Если запретить элементам контролировать отступы и начать задавать отступы отношениям между ними, код станет проще и нагляднее:

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

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

/* Отступ по умолчанию.
   Что бы ни шло после картинки,
   отступ между ней и следующим элементом
   будет равен 72 пк */
.textBox img + * {
  margin-top: 72px;
}
/* Особый отступ в отдельной паре.
   Если после картинки идёт подпись,
   она получает уменьшенный отступ */
.textBox img + .caption {
  margin-top: 18px;
}
Последовательно задаём только верхние отступы, избавились от магических чисел

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

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

Этот же подход работает и в случае, когда отступы явно задаются через специальный элемент‑обёртку, например, .rows или .stack:

Было
/* Элементы внутри .rows и .stack
   считаем «этажами», после которых
   идёт отступ в 72 пк */
.rows > *:not(:last-child) {
  margin-bottom: 72px;
}
/* Аналогичные стили, но с отменой
   отступа у последнего элемента */
.stack > * {
  margin-bottom: 72px;
}
.stack > *:last-child {
  margin-bottom: 0;
}

Стало
.rows > * + * {
  margin-top: 72px;
}
.stack > * + * {
  margin-top: 72px;
}

Ещё по теме

P. S. Это был совет о веб‑разработке. Хотите знать всё о коде, тестах, фронтенд‑разработке, цеэсэсе, яваскрипте, рельсах и джейде? Присылайте вопросы.

Веб‑разработка
Полезно
 17
17
Непонятно
  
Войдите в Бюросферу, чтобы голосовать
Отправить
Поделиться
Запинить

Комментарии

Ещё можно использовать gap грида или флексбокса. Это свойство задаст отступы между дочерними элементами без всяких марджинов:

.stack {
  display: flex;
  flex-direction: column;
  gap: 72px;
}

Получится:

<div class="stack">
  <div />
  <div />
</div>

Вместо того, чтобы задавать отношения между элементами, можно задать набор отступов и пользоваться ими:

<div class="stack stack-lg">
  <div class="stack stack-sm"> ... </div>
  <div class="stack stack-xs" > ... </div>
</div>

Ещё лучше будет, если задать алиасы, чтобы не приходилось гадать, какой отступ подойдёт:

<div class="stack stack-form">
  <div class="stack stack-label"> ... </div>
  <div class="stack stack-buttonGroup" > ... </div>
</div>

Это очень хорошо работает с компонентами:

<Stack gap="form">
  <Stack gap="label"> ... </Stack>
  <Stack gap="buttonGroup" > ... </Stack>
</Stack>

Такой способ очень хорошо подходит и для горизонтальных отступов:

<Row gap="textWithIcon"> <Icon /> <Text> ... </Text> </Row>

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

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

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

Рекомендуем другие советы