Очистка float-элементов посредством создания нового блочного контекста форматирования

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

Задача


Существует некий элемент-контейнер, в котором находится элемент со значением свойства float, установленным как left. Для наглядности у контейнера установлены границы и фон.


jsFiddle

Как видно из примера, контейнер схлопывается — его рассчитанная высота устанавливается в ноль. Этот случай часто встречается в верстке, все к нему привыкли и сложно найти верстальщика, не сталкивавшегося с такой ситуацией.

Почему так происходит?


Дело в том, что если значение свойства height незамещаемого блочного элемента (т.е. контейнера в нашем примере) установлено в auto (а это значение установлено по умолчанию), то его высота определяется исходя из высоты элементов-потомков; при этом в расчет берутся только элементы, участвующие в нормальном потоке. Таким образом, float-элементы и элементы, спозиционированные абсолютно, игнорируются при определении высоты контейнера (ссылка на спецификацию).

Решение


Существует несколько вариантов решения этой задачи.

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

Более продвинутым (и, возможно, лучшим из всех) решением является внедрение класса clearfix, популяризованного уже не твиттеровским Bootstrap’ом и позволяющего добиться того же эффекта без нарушения семантики документа.
Но есть еще одно решение. Оно состоит в том, чтобы задать контейнеру overflow:hidden.


jsFiddle

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

Объяснение


Прежде чем рассмотреть механизм данного явления, отметим, что не только overflow:hidden решает проблему. Контейнер примет высоту float-элемента, если ему задать абсолютную позицию, установить display: inline-block и в некоторых других случаях. Что же происходит на самом деле?

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



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

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

Итак, с понятием контекста разобрались. Теперь ответим на следующий вопрос — почему при создании блочного контекста форматирования float-элементы учитываются для определения высоты контейнера?

Дело в том, что этот случай отдельно оговорен в спецификации. К блокам, создающим новый блочный контекст форматирования и имеющим height:auto (напомню еще раз, что это значение установлено по умолчанию), применяется следующее правило (ссылка на спецификацию):
Если у элемента есть float-потомки, нижняя грань отступов которых находится ниже нижней линии данного элемента, высота данного элемента увеличивается, чтобы вместить эту грань. Только float-элементы, находящиеся в данном блочном контексте форматирования участвуют в этом — например, float-элементы внутри абсолютно спозиционированных потомков или других float-потомков не учитываются.

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

Когда создается новый блочный контекст форматирования


В этой главе перечислены случаи, в которых создается новый контекст форматирования. В контексте проблематики данной статьи этот перечень — список случаев, при которых блок будет подстраиваться по высоте под дочерние float-элементы. Итак, блочный контекст форматирования создается:
  • float-элементами;
  • абсолютно спозиционированными элементами;
  • фиксированными элементами (т.к. position:fixed — разновидность абсолютного позиционирования, ссылка на спецификацию);
  • элементами, представляющими собой блочный контейнер внутри, но имеющими другую структуру снаружи (такие как inline-block, table-cell, table-caption);
  • блоками с overflow установленным в любое значение, кроме visible;
  • элементом fieldset (в большинстве браузеров).


Итого


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

Подробнее
Реклама

Комментарии 18

    +6
    У такого способа есть суровые отрицательные стороны в виде, собственно, overflow:hidden. Использовать следует крайне осторожно.
      +1
      Я использую этот способ вместо clearfix уже более пяти лет. И не вижу ни одной, хоть убейте, отрицательной стороны.
      Этот приём восхитительно работает в случае с height:auto, что составляет около 85% блочной структуры.
      И, разумеется, джедай-верстальщик, применяющий данное свойство прекрасно отдаёт себе отчет в том, как могут себя повести контейнер и содержимое в этом случае.
        +3
        Очевидно, что если какой-то элемент надо будет вынести за пределы контейнера, например иконку, врезку, что угодно, то он обрежется.
          +4
          Из блока с overflow:hidden можно «вытянуть» дочерний элемент.
          Для этого у блока с «overflow:hidden» не должно быть «position», отличного от «static».
          А «position: relative» можно назначить на родительский блок.
          Демо: jsfiddle.net/88fYK/5/
            +4
            А на следующий день внутри блока с overflow: hidden надо будет абсолютно спозиционировать какую-нибудь ерунду, для чего назначить ему position: relative, из-за чего все опять поломается.

            Псевдоэлемент :after с clear:both все же надежнее, если проект не «одноразовый», а будет активно развиваться и меняться.
            • НЛО прилетело и опубликовало эту надпись здесь
              • НЛО прилетело и опубликовало эту надпись здесь
                  0
                  Да и бронзовой нет :)
                  Просто по опыту, среднестатистически, clearfix приносит меньше проблем, чем overflow: hidden.
          0
          Deleted comment. Не заметил радиобаттонов
            0
            За любые решения с какими-либо заданными численными значениями надо расстреливать. Когда-то народ двигал тексты марджинами по 1000px, а потом вдруг оказалось, что у любого задрипанного планшета ширина в два раза больше.
            +2
            Решил я как то раз сделать через хидден…
            … И на следующий день понеслись проблемы: у вложенных элементов тени обрезались. Потом появился апдейт: по ховеру на иконку внутри такого блока выводить тултип, который естественно был не виден… Иногда буквы бывают большие и сверху снизу могу урезаться…
            Вывод: как по мне так минусов полно…
              0
              Тут только .clearfix
              С тенями тоже проходили и с тултипами. Насчет последних есть маленький чит — если тултипы javascript-овые, то можно элемент с тутлипом добавлять в DOM не к элементу с ховером, а к body и позиционировать абсолютно. Самого воротит от такого решения, предпочитаю обходиться css без скриптов.
                0
                Это не чит, а скорее стрельба по мухам из лазерной пушки..))
                0
                У всего есть минусы, просто использовать нужно там, где этот способ подходит. Ну и уметь пользоваться :)
                +1
                Может быть я пропустил, но также высота родителя пересчитается, если ему также указать float: left и width: 100%
                Сам я до недавнего времени пользовался oveflow: hidden и тупым .
                А сейчас я уже перестал бояться, и стал юзать clearfix везде.
                Ну а все эти разговоры про семантику меня по большей части забавляют, нужно просто знать все способы решения задачи, и выбирать тот, который лучше подходит для конкретного случая.
                  0
                  А если родителей много?
                  А если у родителя хочется поставить маргин или паддинг?
                  Поэтому лучше без «float: left и width: 100%».
                  • НЛО прилетело и опубликовало эту надпись здесь

                  Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                  Самое читаемое