Почему этот CSS-стиль не работает? - PullRequest
293 голосов
/ 01 марта 2012

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

Что я ожидал:
What I expected with margin:50px 50px 50px 50px;

Что я получаю:
What I get with margin:50px 50px 50px 50px;

Код:

#outer {
    	width: 500px; 
    	height: 200px; 
    	background: #FFCCCC;
    	margin: 50px auto 0 auto;
    	display: block;
}
#inner {
    	background: #FFCC33;
    	margin: 50px 50px 50px 50px;
    	padding: 10px;
    	display: block;
}
<div id="outer">
  <div id="inner">
  	Hello world!
  </div>
</div>

W3Schools не имеют объяснения, почему маржа ведет себя так.

Ответы [ 11 ]

418 голосов
/ 01 марта 2012

Вы на самом деле видите верхнее поле элемента #inner сворачивается в верхний край элемента #outer, оставляя только поле #outer без изменений (хотя оно и не показано на ваших изображениях).Верхние края обоих полей находятся на одном уровне, потому что их поля равны.

Вот соответствующие точки из спецификации W3C:

8.3.1 Свертывание полей

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

Свертывание вертикальных полей смежности [...]

Два поля примыкают тогда и только тогда, когда:

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

Причина, по которой любое из следующих действий предотвращаетполе от свертывания:

Это потому что:

  • Поля между плавающим блоком и любым другим блоком не разрушаются (даже между плавающим элементом и его дочерними элементами в потоке).
  • Поля элементов, которые устанавливают новые контексты форматирования блока (такие как плавающие элементы и элементы с «переполнением», отличным от «видимого»), не разрушаются со своими дочерними элементами в потоке.
  • Поля блоков встроенного блокане сворачиваться (даже со своими дочерними потоками).

Левое и правое поля ведут себя так, как вы ожидаете, потому что:

Горизонтальные поля никогда не разрушаются.

82 голосов
/ 01 марта 2012

Попробуйте использовать display: inline-block; для внутреннего деления.

#outer {
    width:500px; 
    height:200px; 
    background:#FFCCCC;
    margin:50px auto 0 auto;
    display:block;
}
#inner {
    background:#FFCC33;
    margin:50px 50px 50px 50px;
    padding:10px;
    display:inline-block;
}
19 голосов
/ 10 июня 2015

То, что упоминал @BoltClock, довольно солидно. И здесь я просто хочу добавить еще несколько решений для этой проблемы. отметьте это w3c_collapsing margin . Зеленые части - потенциальная мысль, как решить эту проблему.

Раствор 1

Поля между плавающим блоком и любым другим блоком не разрушаются (даже между плавающим элементом и его дочерними элементами в потоке).

это означает, что я могу добавить float:left к #outer или #inner demo1 .

также обратите внимание, что float сделает недействительным auto в поле.

Решение 2

Поля элементов, которые устанавливают новые контексты форматирования блока (такие как плавающие элементы и элементы с «переполнением», отличным от «видимого»), не разрушаются со своими дочерними элементами в потоке.

кроме visible, давайте поместим overflow: hidden в #outer. И этот способ кажется довольно простым и порядочным. Мне это нравится.

#outer{
    width: 500px;
    height: 200px;
    background: #FFCCCC;
    margin: 50px auto;
    overflow: hidden;
}
#inner {
    background: #FFCC33;
    height: 50px;
    margin: 50px;
}

Раствор 3

Поля абсолютно расположенных ящиков не разрушаются (даже при их дочерних элементах).

#outer{
    width: 500px;
    height: 200px;
    background: #FFCCCC;
    margin: 50px auto;
    position: absolute; 
}
#inner{
    background: #FFCC33;
    height: 50px;
    margin: 50px;
}

или

#outer{
    width: 500px;
    height: 200px;
    background: #FFCCCC;
    margin: 50px auto;
    position: relative; 
}
#inner {
    background: #FFCC33;
    height: 50px;
    margin: 50px;
    position: absolute;
}

эти два метода нарушат нормальный поток div

Решение 4

Поля блоков встроенного блока не сворачиваются (даже при их дочерних элементах в потоке).

совпадает с @ enderskill

Решение 5

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

Это не имеет большого отношения к вопросу, так как это разрыв между братьями и сестрами. как правило, это означает, что в приставке margin-bottom: 30px, а в соседней - margin-top: 10px. Общая разница между ними составляет 30px вместо 40px.

Раствор 6

Верхнее поле элемента блока в потоке сворачивается с верхним полем его первого дочернего элемента уровня потока, если у элемента нет верхней границы, нет верхнего отступа и дочерний элемент не имеет свободного пространства.

Это очень интересно, и я могу просто добавить одну верхнюю границу

#outer{
    width: 500px;
    height: 200px;
    background: #FFCCCC;
    margin: 50px auto;
    border-top: 1px solid red;

}
#inner {
    background: #FFCC33;
    height: 50px;
    margin: 50px;

}

И также <div> по умолчанию является уровнем блока, поэтому вам не нужно объявлять его намеренно. Извините за невозможность опубликовать более 2 ссылок и изображений из-за моей репутации новичка. По крайней мере, вы знаете, откуда возникла проблема, когда в следующий раз увидите нечто подобное.

12 голосов
/ 01 марта 2012

Не знаю, почему то, что у вас есть, не работает, но вы можете добавить

overflow: auto;

до внешнего деления.

10 голосов
/ 01 марта 2012

Если вы добавите какой-либо отступ к #outer, он будет работать.

Демо

#outer {
    width:500px; 
    height:200px; 
    background:#FFCCCC;
    margin:50px auto 0 auto;
    display:block;
    padding-top:1px;
}
10 голосов
/ 01 марта 2012

Не совсем уверен, почему, но изменение внутреннего CSS на

display:inline-block;

, кажется, работает;

2 голосов
/ 01 марта 2012

попробуйте это:

#outer {
    width:500px; 
    height:200px; 
    background:#FFCCCC;
    margin:50px auto 0 auto;
    display:table;
}
#inner {
    background:#FFCC33;
    margin:50px 50px 50px 50px;
    padding:10px;
    display:block;
}​

http://jsfiddle.net/7AXTf/

Удачи

2 голосов
/ 01 марта 2012

Не отвечает на вопрос «почему» (должно быть что-то со складывающимся запасом), но кажется, что самый простой / логичный способ сделать то, что вы пытаетесь сделать, это просто добавить padding-top к внешнему div :

http://jsfiddle.net/hpU5d/1/

Незначительное примечание - нет необходимости устанавливать div в display:block;, если в вашем коде нет чего-то другого, говорящего об этомне быть блоком.

1 голос
/ 07 марта 2012

Используйте padding-top:50px для внешнего div.Примерно так:

#outer {
    width:500px; 
    height:200px; 
    background:#FFCCCC;
    margin:50px auto 0 auto;
    display:table;}

Примечание: заполнение увеличит размер вашего div.В этом случае, если размер вашего div важен, я имею в виду, должен ли он иметь определенную высоту.уменьшить высоту на 50px .:

#outer {
    width:500px; 
    height:150px; 
    background:#FFCCCC;
    margin:50px auto 0 auto;
    display:table;}
1 голос
/ 06 марта 2012

Я полагаю, что установка свойства position для # inner div в относительно также может помочь в достижении эффекта.Но в любом случае я попробовал оригинальный код, вставленный в Вопрос по IE9 и последней версии Google Chrome, и они уже дают желаемый эффект без каких-либо изменений.

...