CSS: чистое решение проблемы с крахом поля при перемещении элемента

Пример HTML + CSS:

<html>
  <body style="padding: 0; margin: 0;">
    <div style="float: right;">first</div>
    <div style="margin-top: 2em;">second</div>
  </body>
</html>

Желаемое поведение: div first плавает в верхнем правом углу окна. Фактическое поведение: он плавает на 2 метка ниже желаемой позиции. Причина: разворот маржи.

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

  • измените стиль body на margin: -1px 0 0 0; border-top: 1px solid;.
  • вставить <div style="height: 1px; margin-bottom: -1px;"></div> до first
  • вставьте выше <div> между first и second

Есть ли чистый, идиоматический способ избежать этой проблемы?

Ответ 1

Добавление overflow: hidden; в body должно решить вашу проблему. Он определяет новый контекст форматирования блоков, как описано в этой статье: Магия переполнения: скрытая.

jsFiddle Demo (тег body автоматически добавляется jsFiddle, поэтому я не включил его в разметку HTML)

UPDATE (спасибо to @clairesuzy): Это решение не работает, если body имеет padding: 0. Пока я не смогу найти лучший способ, я могу предложить только добавить обертку вокруг двух div (по крайней мере, я заслуживаю теперь @Marcel downwote:)), который, как я считаю, более чист, чем решения, размещенные OP. Я обычно добавляю обертку вокруг плавающего материала в любом случае (упрощает обработку старых браузеров большую часть времени), большую часть времени его не нужно добавлять намеренно, потому что это логически и семантически требуется.

Итак, теперь я могу придумать это:

<body style="padding: 0; margin: 0;">
   <div id="container" style="overflow: hidden;">
       <div style="float: right;">first</div>
       <div style="margin-top: 2em;">second</div>
   </div>
</body>

jsFiddle Demo

ОБНОВЛЕНИЕ 2. Подумав об этом и прочитав комментарии, я действительно думаю, что overflow: hidden (или что-либо другое, кроме overflow: visible) на контейнере является правильным решением. Единственное исключение, в котором он не работал у меня, - это установить его на элемент body, что очень редко встречается. В этих редких ситуациях вы можете попробовать использовать position: absolute; top: 0; right: 0; вместо того, чтобы плавать.

Еще одно возможное обходное решение: я также обнаружил, что установка display: inline-block; width: 100%; на body действительно работает.

jsFiddle Demo

Ответ 2

В родительском div добавьте это #parent {padding 1px 0; }, это было огромной проблемой для меня, и навсегда потребовалось найти решение. Я видел на почте, как 2 года, и это устраняет крах.

Ответ 3

Решение

добавить overflow: auto; или overflow: hidden; или overflow: scroll; в теги html и body.

ЕСЛИ ВЫ ХОТИТЕ ЗНАТЬ ПОЧЕМУ

Создание контекста форматирования блока (BFC) в теге body.

Почему это не работает, если я добавляю overflow: hidden; только к body?

Вот почему:

W3С# блочное форматирование

Поплавки, абсолютно позиционированные элементы, блокировать контейнеры (например, встроенные блоки, таблицы-ячейки и заголовки таблиц), которые не являются блочными блоками, и блокировать блоки с "переполнением", отличным от "видимого" (исключая когда это значение было распространено в окне просмотра), создайте контексты форматирования блоков для их содержимого.

Переполнение W3С#:

UA должны применять свойство переполнения в корневом элементе к окну просмотра.

Когда корневой элемент является элементом HTML "HTML" или элементом "html" XHTML, и этот элемент имеет элемент HTML "BODY" или элемент "тело" XHTML в качестве дочернего элемента, пользовательские агенты должны вместо этого применять ' overflow 'из первого такого дочернего элемента в окне просмотра, если значение в корневом элементе "видимо" .

"Видимое" значение, используемое для окна просмотра, должно интерпретироваться как "авто".

Элемент, из которого распространяется значение, должен иметь использованное значение для "переполнения" "видимого" .

the first such child element и The element from which the value is propagated относятся к тегу body в этом случае.

Другими словами, если вы добавляете overflow: hidden; или overflow: auto; или overflow: scroll; в body, а значение свойства html overflow остается неизменным, значение свойства body overflow hidden или auto или scroll) будут переданы в окно просмотра. Таким образом, согласно первой цитате W3C, body не будет устанавливать новый контекст форматирования блока.

Однако, если вы добавите overflow: hidden; или overflow: auto; или overflow: scroll; в html, значение overflow 'body' не будет распространено и, следовательно, создаст новый контекст форматирования блока.

Ответ 4

Добавьте float: left; во второй div.

fiddle

Ответ 5

Спецификации W3C описывают это о сворачивающихся границах:

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

http://www.w3.org/TR/CSS21/box.html#collapsing-margins

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

если край сжимался сверху.. затем:

#element-with-collapsed-margin {
   padding-top:1px;
}

или border-top также исправит это.

#element-with-collapsed-margin {
   border-top:1px solid transparent;
}

если ваше нижнее поле свернуто, тогда вы добавите padding-bottom: 1px; или border-top: 1px solid transparent;

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

Хорошая ссылка:

http://reference.sitepoint.com/css/collapsingmargins

..

Ответ 6

Другой трюк, который вы можете использовать, когда overflow:hidden не подходит:

.clr:before, .clr:after {
    display: table;
    content: " ";
    clear: both;
    font-size: 0;
}

Этот фрагмент имеет побочный эффект, содержащий все поплавки.

Ответ 7

Это может быть странно, но в новых версиях Chrome и Mozilla вы можете добиться желаемого поведения (первый div находится в верхнем правом углу), добавив оболочку div с рамкой

<html>
  <body style="padding: 0; margin: 0;">
    <div style="border: 1px solid black">
        <div style="float: right;">first</div>
        <div style="margin-top: 2em;">second</div>
    </div>
  </body>
</html>