CSS-live.ru

Варианты «clearfix-хака» и его замен: сводная таблица

Вдогонку статье о новом значении свойства display, призванном избавить верстальщиков от нужды в clearfix-хаках — своего рода «шпаргалка», показывающая, в чем именно бывают проблемы с float-ами и какие из решений — исторических, теперешних и перспективных — какие из этих проблем решают (а какие — создают взамен:).

Первая строка таблицы — поведение обычного блока, без всяких что-то-фиксов. Хороший фикс должен исправить только то, что нам мешает, по возможности сохранив остальное поведение блока — которое нас вполне устраивает — неизменным. А именно:

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

При этом мы хотим, чтобы:

  • float-ы не «вываливались» из блока — его высота учитывала их (именно это обычно подразумевают, говоря «заклирить флоаты»:);
  • но и float-ы, идущие в потоке раньше, не «вваливались» в него, влияя на поведение контента блока, включая его внутренние float-ы (об этом часто забывают, что приводит к неприятным сюрпризам);
  • margin-ы дочерних элементов блока не «схлопывались» с margin-ами самого блока и его соседей (вообще-то для сплошного текста «схлопывание» скорее полезно, есть много доводов в его защиту, но будем честны перед собой: в подавляющем большинстве макетов никаких «выпадающих margin-ов» блоки не предусматривают).

И, само собой, это должно работать во всех браузерах. В следующей таблице видно, насколько каждое решение этим требованиям удовлетворяет.

Способ «Клирит» флоаты? Изоли­рует от внеш­них float-ов? Запре­щает выва­лива­ние margin-ов? Впи­сыва­ется в свобо­дное место по ширине? Запол­няет свобо­дное место при узком кон­тенте? Широ­кий кон­тент пере­пол­няет кон­тейнер, не рас­пирая? Не обре­зает высту­пающий кон­тент? Кросс­брау­зерно?
display:block по умолчанию

Только контент1

Решения на основе clear (в том же контексте форматирования)

Отдельный элемент с clear

2

Только контент1

Micro clearfix Галлахера

Только контент1

btc-сlearfix Кобленца

Только снизу3

Только контент1

Новейший clearfix Кобленца

2

Только контент1

Решения, создающие отдельный контекст форматирования

hasLayout (zoom:1 и т.п.)

Только IE7-

overflow: hidden (или auto)

4

display: table

display: table-cell

display: table с хаком-распоркой

display: inline-block

float

Элемент fieldset

5

column-count: 1

6

IE10+6

column-span: all

Пока ✘

display: flow-root (стандартный способ)

Пока ✘

contain: layout (тоже может стать стандартным)

Только Blink

Примечания к таблице:

1 По умолчанию блок может перекрываться с высокими float-ами, идущими в потоке раньше — они могут «проникать» в него, смещая его контент. Это стандартное поведение для блоков с текстом, но от блоков-контейнеров мы обычно ждем, чтобы они были полностью изолированы от любых других блоков. Без отдельного блочного контекста форматирования это проблематично.

2 Из-за схлопывания нижнего margin-а блока и его дочернего элемента блока возможна ситуация, когда float целиком поместится в этом объединенном margin-е, а блочный элемент с clear формально окажется под ним. Визуально это выглядит так, будто clear не сработал. Именно поэтому для clearfix-хака рекомендовали display:table, а не display:block — через «прокладку» в виде таблицы, как элемент с новым контекстом форматирования (даже нулевого размера!), margin-ы схлопнуться не могут, и clearfix сработает всегда. Вот утрированный, но вполне реалистичный пример этого различия.

3 ::after с display:table не дает нижним margin-ам дочерних элементов блока «вывалиться» за его границу и «схлопнуться» с margin-ом самого блока. Но верхним margin-ам в этом способе, в отличие от предыдущего, ничего «схлопнуться» не мешает.

4 В CSS2.x есть неочевидная и малоизвестная особенность, что overflow:hidden не обрезает вложенные элементы блока, абсолютно позиционированные относительно его предка. Так что, если сделать блок с двойной оберткой — position: relative у внешней и overflow у внутренней — обрезки выступающего контента можно частично избежать. Но лишь частично, так как непозиционированный контент (выдвинутый наружу margin-ами, трансформациями и т.д.) обрежется в любом случае. В варианте с overflow:auto выступающий контент остается доступен за прокруткой, но далеко не всегда это приемлемо по дизайну.

5 По умолчанию для fieldset приоритетна ширина контента, а не контейнера (как и у таблицы). Потому что в браузерных стилях (у новых браузеров) ему задано min-width: min-content. Это можно переопределить (в некоторых браузерах — лишь хаками).

6 По актуальному стандарту контент, выступающий из колончатого контейнера, обрезаться не должен (хотя в прошлых редакциях это то и дело менялось и долго шел спор о трактовке). Но в некоторых браузерах с этим бывали баги. Надо тщательно тестировать!

Также не забывайте, что значения display, меняющие внешнее поведение блока, могут приводить к добавочным сюрпризам. Например, с display:inline-block элемент переносится из блочного контекста форматирования в инлайновый, а с display:table-cell — оборачивается в анонимный блок с табличным контекстом (и начинает игнорировать свойство margin).

Наглядно посмотреть и «пощупать» почти все описанные здесь особенности можно на интерактивных примерах из предыдущей статьи (для удобства второй пример дублирую прямо здесь). Замечания, дополнения и уточнения в комментариях приветствуются!

See the Pen Способы создания БКФ by Ilya Streltsyn (@SelenIT) on CodePen.

P.S. Это тоже может быть интересно:

5 комментариев

    1. Упс, главное, в пример в предыдущей статье добавил, а в сводной таблице забыл). Именно из-за редкости применения, видимо.

      Добавил упоминание в таблицу. Спасибо!

      1. А ещё position: absolute|fixed (но решение сомнительное).

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

        Проблема будет в таком случае:

        .float

        .our-block

        .float // Можно и без внутреннего float’а

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

  1. Хочу подчеркнуть ещё одно различие между вышеописанными методами.

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

    P.S. Новый дизайн супер. Теперь современно и приятно для глаз:)

  2. Хочу подчеркнуть ещё одно различие между вышеописанными методами.

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

    P.S. Новый дизайн супер. Теперь современно и приятно для глаз:)

Оставить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

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