Контексты блочного форматирования, сворачивание полей и плавающие контейнеры

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

Я взял следующее демо из " Все, что вы знаете о Clearfix неправильно":

.wrapper {
  width: 740px;
  background: #cccccc;
}
.leftSidebar {
  float: left;
  width: 200px;
}
.rightSidebar {
  float: right;
  width: 200px;
}
.mainContent {
  padding-right: 200px;
  padding-left: 200px;
}
.floatMe {
  float: left;
  background: teal;
  color: #fff;
}
<div class="wrapper">
  <div class="leftSidebar">
    <h2>Heading</h2>
    <pre>.leftSidebar {
  float:left;
  width:200px;
}</pre>
  </div>
  <div class="rightSidebar">
    <h2>Heading</h2>
    <pre>.rightSidebar {
  float:right;
  width:200px;
}</pre>
  </div>
  <div class="mainContent">
    <h2>Heading</h2>
    <pre>.mainContent {
  padding-right:200px;
  padding-left:200px;
}</pre>
    <div class="floatMe">
      <pre>.floatMe {
  float:left;
  background:teal;
  color:#fff;
}</pre>
    </div>
  </div>
</div>

Согласно этой статье (выделение мое):

В современных браузерах:

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

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

Я попытался выяснить точный макет, добавив * {border: 1px solid blue;} в CSS, но общий макет сильно изменился после этого изменения: теперь он ведет себя так, как будто wrapper является контекстом форматирования блока!

.wrapper {
  width: 740px;
  background: #cccccc;
}
.leftSidebar {
  float: left;
  width: 200px;
}
.rightSidebar {
  float: right;
  width: 200px;
}
.mainContent {
  padding-right: 200px;
  padding-left: 200px;
}
.floatMe {
  float: left;
  background: teal;
  color: #fff;
}
* {
  border: 1px solid blue;
}
<div class="wrapper">
  <div class="leftSidebar">
    <h2>Heading</h2>
    <pre>.leftSidebar {
  float:left;
  width:200px;
}</pre>
  </div>
  <div class="rightSidebar">
    <h2>Heading</h2>
    <pre>.rightSidebar {
  float:right;
  width:200px;
}</pre>
  </div>
  <div class="mainContent">
    <h2>Heading</h2>
    <pre>.mainContent {
  padding-right:200px;
  padding-left:200px;
}</pre>
    <div class="floatMe">
      <pre>.floatMe {
  float:left;
  background:teal;
  color:#fff;
}</pre>
    </div>
  </div>
</div>

Пожалуйста, скажи мне, что происходит.

1 ответ

Хороший вопрос, заставил меня много думать!

Здесь много понятий, поэтому я расскажу о них один за другим:

Багги IE:

Все, что упомянуто в этой старой статье об IE, можно легко проигнорировать, если вам не нужно разрабатывать для режима совместимости IE7 или IE8. Такое поведение связано со свойством hasLayout, используемым внутри IE7.

Смотрите этот документ MSDN для IE7:

Что такое "HasLayout" и почему это важно?

В Internet Explorer есть несколько ошибок, которые можно обойти, используя "макет" (внутреннюю структуру данных IE) для элемента.

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


Контекст форматирования блока (BFC):

Выдержки из этого документа MDN:

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

BFC очень важны для позиционирования и очистки всплывающих элементов - плавающие элементы воздействуют только в пределах тех же BFC. Когда ты float элемент, он берется из потока и вставляется "плавающим".

Смотрите примеры ниже:

  1. Внутри wrapper это BFC, где вы плаваете один div слева, а другой справа.

  2. Плавающие элементы повторно вставляются в BFC при рендеринге вокруг элемента, который не является плавающим.

  3. Как у вас нет clear плавание в BFC, wrapper высота будет расширяться до размера элемента, который не является плавающим.

        body{
          margin: 0;
        }
        *{
          box-sizing: border-box;
        }
        .wrapper{
          border: 1px solid;
        }
        .wrapper > * {
          display: inline-block;
          border: 1px solid red;
          width: 33.33%;
          height: 100px;
        }
        .left{
          float: left;
        }
        .right{
          float: right;
        }
        .center{
          height: 50px;
        }
        <div class="wrapper">
          <div class="left">Left</div>
          <div class="center">Center</div>
          <div class="right">Right</div>
        </div>

  4. Посмотрите, что происходит, когда вы clear плавающий в BFC- теперь высоты будут вести себя нормально в wrapper BFC.

        body{
          margin: 0;
        }
        *{
          box-sizing: border-box;
        }
        .wrapper{
          border: 1px solid;
        }
        .wrapper > * {
          display: inline-block;
          border: 1px solid red;
          width: 33.33%;
          height: 100px;
        }
        .left{
          float: left;
        }
        .right{
          float: right;
        }
        .center{
          height: 50px;
        }
        .wrapper:after{
          content: '';
          display: block;
          clear: both;
        }
        <div class="wrapper">
          <div class="left">Left</div>
          <div class="center">Center</div>
          <div class="right">Right</div>
        </div>


Сокращение полей:

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

Поля свернуты для смежных блоков, родительских и первых / последних дочерних и пустых блоков. Подробнее о падении маржи читайте в этом документе MDN.

Также обратите внимание, что:

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



Так что на самом деле здесь происходит?

  1. Итак, теперь вы поймете о BFC, а также о том, как работают плавающие контейнеры в первом случае (когда у вас нет заданных границ) - вот почему floatMe остается вне его непосредственного mainContent обертка и почему именно высота wrapper а также mainContent как это выглядит там.

  2. Макет и IE упоминаются только в IE7 и являются нестандартными.

  3. Все остальное происходит из-за обвала полей:

    а. h2 а также pre Свернуть поля (смежные братья и сестры)

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

    с. Как wrapper принимает высоту mainContent, wrapper высота также смещена вверх.

    д. Когда вы применяете границы, происходит то, что поле, свернутое в (b) выше, обнуляется! (см. MDN doc выше относительно того, почему)



Надеюсь, сейчас все выглядит лучше. Ура!

Другие вопросы по тегам