7 июня 2022 г.

Свойство margin

Свойство margin задаёт отступы вокруг элемента. У него есть несколько особенностей, которые мы здесь рассмотрим.

Объединение отступов

Вертикальные отступы поглощают друг друга, горизонтальные – нет.

Например, вот документ с вертикальными и горизонтальными отступами:

<body style="background: #aef">
  <p style="margin:20px; background:white">

    <span style="margin:20px; background:orange">Горизонтальный 20px</span>
    ← 40px →
    <span style="margin:20px; background:orange">20px Отступ </span>

  </p>
  <p style="margin:15px; background:white">Вертикальный 20px</p>
</body>

Расстояние по горизонтали между элементами SPAN равно 40px, так как горизонтальные отступы по 20px сложились.

А вот по вертикали расстояние от SPAN до P равно 20px: из двух вертикальных отступов выбирается больший max(20px, 15px) = 20px и применяется.

Отрицательные margin-top/left

Отрицательные значения margin-top/margin-left смещают элемент со своего обычного места.

В CSS есть другой способ добиться похожего эффекта – а именно, position:relative. Но между ними есть одно принципиальное различие.

При сдвиге через margin соседние элементы занимают освободившееся пространство, в отличие от position: relative, при котором элемент визуально сдвигается, но место, где он был, остаётся «занятым».

То есть, элемент продолжает полноценно участвовать в потоке.

Пример: вынос заголовка

Например, есть документ с информационными блоками:

<style>
  div {
    border: 1px solid blue;
    margin: 2em;
    font: .8em/1.25 sans-serif;
  }

  h2 {
    background: #aef;
    margin: 0 0 0.8em 0;
  }
</style>

<div>
  <h2>Общие положения</h2>

  <p>Настоящие Правила дорожного движения устанавливают единый порядок дорожного движения на всей территории Российской Федерации. Другие нормативные акты, касающиеся дорожного движения, должны основываться на требованиях Правил и не противоречить им.</p>
</div>

<div>
  <h2>Общие обязанности водителей</h2>

  <p>Водитель механического транспортного средства обязан иметь при себе и по требованию сотрудников милиции передавать им для проверки:</p>
  <ul>
    <li>водительское удостоверение на право управления транспортным средством соответствующей категории;</li>
    <li>...и так далее...</li>
  </ul>
</div>

Использование отрицательного margin-top позволяет вынести заголовки над блоком.

/* вверх чуть больше, чем на высоту строки (1.25em) */

h2 {
  margin-top: -1.3em;
}

Результат:

А вот, что бы было при использовании position:

h2 {
  position: relative;
  top: -1.3em;
}

Результат:

При использовании position, в отличие от margin, на месте заголовков, внутри блоков, осталось пустое пространство.

Пример: вынос разрыва

Организуем информацию чуть по-другому. Пусть после каждого заголовка будет разрыв:

<div>
  <h2>Заголовок</h2>
  <hr>

  <p>Текст Текст Текст.</p>
</div>

Пример документа с такими разрывами:

Для красоты мы хотим, чтобы разрыв HR начинался левее, чем основной текст. Отрицательный margin-left нам поможет:

/*+ no-beautify */
hr.margin { margin-left: -2em; }

/* для сравнения */
hr.position { position: relative; left: -2em; }

Результат:

Обратите внимание на разницу между методами сдвига!

  • hr.margin сначала сдвинулся, а потом нарисовался до конца блока.
  • hr.position сначала нарисовался, а потом сдвинулся – в результате справа осталось пустое пространство.

Уже отсюда видно, что отрицательные margin – исключительно полезное средство позиционирования!

Отрицательные margin-right/bottom

Отрицательные margin-right/bottom ведут себя по-другому, чем margin-left/top. Они не сдвигают элемент, а «укорачивают» его.

То есть, хотя сам размер блока не уменьшается, но следующий элемент будет думать, что он меньше на указанное в margin-right/bottom значение.

Например, в примере ниже вторая строка налезает на первую:

<div style="border: 1px solid blue; margin-bottom: -0.5em">
  Первый
</div>

<div style="border: 1px solid red">
  Второй div думает, что высота первого на 0.5em меньше
</div>

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

Например:

Итого

  • Отрицательные margin-left/top сдвигают элемент влево-вверх. Остальные элементы это учитывают, в отличие от сдвига через position.
  • Отрицательные margin-right/bottom заставляют другие элементы думать, что блок меньше по размеру справа-внизу, чем он на самом деле.

Отличная статья на тему отрицательных margin: The Definitive Guide to Using Negative Margins

Задачи

важность: 3

В примере ниже находится блок .block фиксированной высоты, а в нём – прямоугольник .spacer.

При помощи margin-left: 20% и margin-right: 20%, прямоугольник центрирован в родителе по горизонтали. Это работает.

Далее делается попытка при помощи свойств height: 80%, margin-top: 10% и margin-bottom: 10% расположить прямоугольник в центре по вертикали, чтобы сам элемент занимал 80% высоты родителя, а сверху и снизу был одинаковый отступ.

Однако, как видите, это не получается. Почему? Как поправить?

<style>
  .block {
    height: 150px;

    border: 1px solid #CCC;
    background: #eee;
  }

  .spacer {
    margin-left: 20%;
    margin-right: 20%;

    height: 80%;
    margin-top: 10%;
    margin-bottom: 10%;

    border: 1px solid black;
    background: #FFF;
  }
</style>

<div class="block">
  <div class="spacer"></div>
</div>

Ошибка заключается в том, что margin при задании в процентах высчитывается относительно ширины. Так написано в стандарте.

При этом не важно, какой отступ: левый, правый. верхний или нижний. Все они в процентах отсчитываются от ширины. Из-за этого и ошибка.

Ситуацию можно исправить, например, заданием margin-top/margin-bottom в пикселях, если это возможно или, в качестве альтернативы, использовать другие средства, в частности, position или padding-top/padding-bottom на родителе.

важность: 5

Создайте <input type="password"> с цветной подсказкой внутри (должен правильно выглядеть, не обязан работать):

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

P.S. Обратите внимание: type="password"! То есть, просто value использовать нельзя, будут звёздочки. Кроме того, подсказка, которую вы реализуете, может быть как угодно стилизована.

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

Открыть песочницу для задачи.

Подсказка

Надвиньте элемент с текстом на INPUT при помощи отрицательного margin.

Решение

Надвинем текст на INPUT при помощи отрицательного margin-top. Поднять следует на одну строку, т.е. на 1.25em, можно для красоты чуть больше – 1.3em:

Также нам понадобится обнулить «родной» margin у INPUT, чтобы не сбивал вычисления.

<style>
  input {
    margin: 0;
    width: 12em;
  }

  #placeholder {
    color: red;
    margin: -1.3em 0 0 0.2em;
  }
</style>

<input type="password" id="input">
<div id="placeholder">Скажи пароль, друг</div>

Открыть решение в песочнице.

Карта учебника

Комментарии

перед тем как писать…
  • Если вам кажется, что в статье что-то не так - вместо комментария напишите на GitHub.
  • Для одной строки кода используйте тег <code>, для нескольких строк кода — тег <pre>, если больше 10 строк — ссылку на песочницу (plnkr, JSBin, codepen…)
  • Если что-то непонятно в статье — пишите, что именно и с какого места.