Варианты «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. Это тоже может быть интересно:
Еще встречал overflow: auto, если высота не задана, хотя сам почти не применял.
Упс, главное, в пример в предыдущей статье добавил, а в сводной таблице забыл). Именно из-за редкости применения, видимо.
Добавил упоминание в таблицу. Спасибо!
А ещё position: absolute|fixed (но решение сомнительное).
Возможно что это само собой разумеющееся, но всё же хочу сказать, что наш родительский блок будет обтекать предыдущие элементы, которым задан float, данное будет происходить при всех clearfix’ах и при создании контекста форматирования.
Проблема будет в таком случае:
Чтобы это исправить нам нужно растянуть наш блок по ширине так, чтобы он не вмещался вместе с предыдущими обтекающими блоками в один ряд. Или же задать ему самому свойство clear.
Хочу подчеркнуть ещё одно различие между вышеописанными методами.
В большинстве случаев поле контейнера проваливается под внешние плавающие элементы, такого не происходит, например, в случае, когда мы сам контейнер делаем плавающим элементом.
P.S. Новый дизайн супер. Теперь современно и приятно для глаз:)
Хочу подчеркнуть ещё одно различие между вышеописанными методами.
В большинстве случаев поле контейнера проваливается под внешние плавающие элементы, такого не происходит, например, в случае, когда мы сам контейнер делаем плавающим элементом.
P.S. Новый дизайн супер. Теперь современно и приятно для глаз:)