Маржа на дочернем элементе перемещает родительский элемент


415

У меня есть div( родитель ), который содержит другой div( ребенок ). Родитель - это первый элемент bodyбез определенного стиля CSS. Когда я установил

.child
{
    margin-top: 10px;
}

Конечным результатом является то, что вершина моего ребенка все еще выровнена с родителем. Вместо того, чтобы переместить ребенка на 10px вниз, мой родитель переместился на 10px вниз.

Мой DOCTYPEнастроен на XHTML Transitional.

Что мне здесь не хватает?

edit 1
Мой родитель должен иметь строго определенные размеры, потому что у него есть фон, который должен отображаться под ним сверху вниз (в идеальном пикселе). Таким образом , установка вертикальных полей на нем не является не идти .

edit 2
Это поведение одинаково на FF, IE, а также CR.


188
это поведение не имеет смысла, что так всегда. Предполагается, что маржа остается внутри родителя. Не двигайте родителя. Кто пишет эти правила.
Мухаммед Умер

10
+2 за последний комментарий. серьезно, это правило меня беспокоит. «60% времени это работает каждый раз» - это наценки.
Кейси Дуэйн

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

1
Это также может помочь вам :) stackoverflow.com/questions/35337043/…
Бходжандра Раунияр

5
Это напоминает мне правило размера ящика по умолчанию: « Нам нужно отправить ящик. Ящик не должен быть больше 100 см. Нам нужно 10 см заполнения внутри ящика, чтобы наш контент не сломался во время доставки. Давайте сделаем коробка 120см! Какая шутка.
Нолонар

Ответы:


492

Находите альтернативу в дочерних элементах с полями в DIV. Вы также можете добавить:

.parent { overflow: auto; }

или:

.parent { overflow: hidden; }

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

.parent {
    padding-top: 1px;
    margin-top: -1px;
}

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

h1, h2, p, ul {
  margin-top: 1em;
  margin-bottom: 1em;
}
<h1>Title!</h1>
<div class="text">
  <h2>Title!</h2>
  <p>Paragraph</p>
</div>
<div class="text">
  <h2>Title!</h2>
  <p>Paragraph</p>
  <ul>
    <li>list item</li>
  </ul>
</div>

Поскольку браузер сворачивает поля, текст будет выглядеть так, как вы ожидаете, а <div>теги-обертки не влияют на поля. Каждый элемент обеспечивает интервал вокруг него, но интервал не будет удвоен. Края <h2>и <p>не складываются, а скользят друг в друга (они рушатся). То же самое происходит для <p>и <ul>элемента.

К сожалению, с современным дизайном эта идея может укусить вас, когда вы явно хотите контейнер. Это называется новым контекстом форматирования блока в CSS. overflowИли запас трюк даст вам это.


41
Я хочу знать, почему это происходит, что это хорошо для всех. В какой ситуации эта «особенность» должна была быть.
Мухаммед Умер

2
@ MuhammadUmer, ну это связано с текстовым контентом. Например, серия <h2>, <p>, <ul>не получит странные пробелы или «двойные» поля таким образом.
vdboor

7
Не могли бы вы привести пример. Допустим, у меня есть div в качестве фона. С h1, h2 и p в нем. Теперь я хочу немного сдвинуть h1 вниз, чтобы он не был так близок к верхнему краю фонового элемента div, но не раскрывал сам элемент h1. Я думаю, что добавить верхнее поле. Что очевидно. но когда я делаю это, великолепный фон решает двигаться вместе с ним. Как это особенность. Как это помогает в интервале между h1, h2 и p. Помоги мне понять, что ты говоришь.
Мухаммед Умер

1
Я добавил для вас пример
vdboor

3
Я ожидаю, что это добавит больше маржи. Снижение рентабельности - самая раздражающая вещь в моей карьере разработчика. если я поставлю 2 деления рядом друг с другом с margin: 5px 10px;id, ожидаем 2 деления 5 пикселей сверху и 20 пикселей между ними, а не 5 пикселей сверху и 10 пикселей между ними. если бы я хотел, чтобы 10 пикселей между ними указали id margin: 5px 5px;. я искренне желаю, чтобы было корневое правило, которое я мог бы разместить, чтобы остановить падение всех полей. я ненавижу, что мне приходится удваивать размер полей на бумаге, чтобы заставить их делать то, что я хочу на экране. и это главное ... какая катастрофа
Дж. Л. Гриффин,

50

Это нормальное поведение (по крайней мере, среди реализаций браузера). Поля не влияют на позицию дочернего элемента по отношению к его родителю, если только у родительского элемента нет отступов, и в этом случае большинство браузеров добавят поле дочернего элемента к отступам родителя.

Чтобы получить желаемое поведение, вам необходимо:

.child {
    margin-top: 0;
}

.parent {
    padding-top: 10px;
}

3
Добавление границы к родителю также повлияет на маржу ребенка, попробуйте.parent {border: solid 1px;}
ОК,

1
Поле не добавляет к отступу ... оно применяется отдельно. Но визуальный эффект тот же.
Brilliand

1
Что делать, если вы хотите получить максимальную прибыль ...? Не совсем решение.
feeela

3
Как сказала Фила, на самом деле это не решение, если требуется верхнее поле. Ответ Vdboor подходит лучше.
Джои Морани

1
Есть куча решений, вам просто нужно быть достаточно креативным. Приветствия. :-)
Славик Мельцер

24

Хотя все ответы решают проблему, но они идут с компромиссами / корректировками / компромиссами, такими как

  • floats, У вас есть плавать элементы
  • border-top, Это толкает -1pxродительский элемент как минимум на 1 пиксель вниз, что затем должно быть скорректировано с введением маржи для самого родительского элемента. Это может создать проблемы, когда родитель уже имеет margin-topотносительные единицы.
  • padding-topтот же эффект, что и при использовании border-top
  • overflow: hidden, Не может использоваться, когда родитель должен отображать переполненный контент, например выпадающее меню
  • overflow: auto, Вводит полосы прокрутки для родительского элемента, который имеет (намеренно) переполнение содержимого (например, тени или треугольник подсказки)

Проблема может быть решена с помощью псевдоэлементов CSS3 следующим образом

.parent::before {
  clear: both;
  content: "";
  display: table;
  margin-top: -1px;
  height: 0;
}

https://jsfiddle.net/hLgbyax5/1/


margin-top: -1pxкажется ненужным. Но мне это нравится.
Flimm

3
На самом деле и то margin-top: -1pxи другое height: 0кажется ненужным. Проверено в Chrome. Но лучшее решение.
NinjaFart

Этот метод в основном работает, но не учитывает нижнее поле для последнего элемента в контейнере. Это не то же самое, что переполнение: скрытый; например.
Майкл Джованни Пумо

1
@MichaelGiovanniPumo ответ может быть изменен для работы с нижним полем последнего элемента с помощью.parent:after...
Ejaz

Это, безусловно, правильный ответ в наши дни. Работает безупречно (надевайте как после, так и до), я надеюсь, что люди смеют пролистывать другие!
fgblomqvist


9

родительский элемент не должен быть пустым, по крайней мере, &nbsp;перед дочерним элементом.


2
да, иногда только это может помочь ... или лучше поставить что-то вроде этого: <div style = 'width: 0; height: 0'> & nbsp; </ div>
Пигалев Павел


2

Я обнаружил, что внутри вашего .css> если вы установите свойство display элемента div в inline-block, это решит проблему. и маржа будет работать так, как ожидается.


2

Оптимальное CSS-решение

Используйте следующий код для добавления бездетного первого ребенка к непреднамеренно движущемуся div:

.parent:before
{content: '';position: relative;height: 0px;width: 0px;overflow: hidden;white-space: pre;}

Преимущество этого метода заключается в том, что вам не нужно изменять CSS любого существующего элемента, и, следовательно, он оказывает минимальное влияние на дизайн. Кроме того, добавляемый элемент является псевдоэлементом, которого нет в DOM-дереве.

Поддержка псевдоэлементов широко распространена: Firefox 3+, Safari 3+, Chrome 3+, Opera 10+ и IE 8+. Это будет работать в любом современном браузере (будьте осторожны с более новым ::before, который не поддерживается в IE8).

контекст

Если первый дочерний элемент элемента имеет margin-top, родительский объект будет корректировать свою позицию как способ свертывания избыточных полей. Почему? Это просто так.

Учитывая следующую проблему:

<style type="text/css">
div {position: relative;}
.parent {background-color: #ccc;}
.child {margin-top: 40px;}
</style>

<div class="parent"><!--This div moves 40px too-->
    <div class="child">Hello world!</div>
</div>

Вы можете исправить это, добавив дочерний элемент с таким содержимым, как простое пространство. Но мы все ненавидим добавлять пробелы для решения проблемы, связанной только с дизайном. Поэтому используйте white-spaceсвойство для фальсификации контента.

<style type="text/css">
div {position: relative;}
.parent {background-color: #ccc;}
.child {margin-top: 40px;}
.fix {position: relative;white-space: pre;height: 0px;width: 0px;overflow: hidden;}
</style>

<div class="parent"><!--This div won't move anymore-->
    <div class="fix"></div>
    <div class="child">Hello world!</div>
</div>

Где position: relative;обеспечивает правильное расположение исправления. И white-space: pre;избавляет вас от необходимости добавлять какой-либо контент - например, пробел - в исправление. И height: 0px;width: 0px;overflow: hidden;гарантирует, что вы никогда не увидите исправление.

Возможно, вам придется добавить line-height: 0px;или max-height: 0px;убедиться, что высота на самом деле равна нулю в древних браузерах IE (я не уверен). И по желанию вы можете добавить <!--dummy-->к нему в старых браузерах IE, если он не работает.

Короче говоря, вы можете сделать все это только с помощью CSS (что устраняет необходимость добавления фактического дочернего элемента в HTML-дерево DOM):

<style type="text/css">
div {position: relative;}
.parent {background-color: #ccc;}
.child {margin-top: 40px;}

.parent:before {content: '';position: relative;height: 0px;width: 0px;overflow: hidden;white-space: pre;}
</style>

<div class="parent"><!--This div won't move anymore-->
    <div class="child">Hello world!</div>
</div>

Используйте это решение только в том случае, если вы в отчаянии и не можете установить какой-либо пользовательский CSS для существующих элементов - в противном случае используйте реальное решение: установить overflow: hidden;для родителя.
Йети

2

Чтобы предотвратить "Div parent", используйте поле "div child":
В parent используйте эти css:

  • терка
  • набивка
  • бордюр
  • перелив

1

marginЭлементов содержится внутри .childразрушаются.

<html>
<style type="text/css" media="screen">
    #parent {background:#dadada;}
    #child {background:red; margin-top:17px;}
</style>
<body>
<div id="parent">

    <p>&amp;</p>

    <div id="child">
        <p>&amp;</p>    
    </div>

</div>
</body>
</html>

В этом примере pполучает marginиз браузера стили по умолчанию. По умолчанию браузер font-sizeобычно 16px. Имея margin-topболее 16 пикселей, #childвы начинаете замечать, что он перемещается на позицию.


1

У меня тоже была эта проблема, но я предпочел предотвратить взломы с отрицательной маржей, поэтому я поставил

<div class="supercontainer"></div>

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


1

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

HTML:

<div class="parent">
    <div class="child"></div>
</div>

CSS:

.parent{width:100px; height:100px;}
.child{float:left; margin-top:20px; width:50px; height:50px;}

увидеть это здесь: http://codepen.io/anon/pen/Iphol

обратите внимание, что в случае, если вам нужна динамическая высота для родителя, она также должна плавать, поэтому просто замените height:100px;наfloat:left;


1

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

Ваша коробка будет использовать дополнительные пиксели, хотя ...

.parent {
    border:1px solid transparent;
}

0

Использование topвместо margin-topдругого возможного решения, если это уместно.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.