.clearfix — который так полюбился большинству верстальщиков, его использование мотивируется простотой и отсутствием других способов работы с float блоками. Хочу представить вашему вниманию другой способ — не менее действенный и не более сложный. Хотя по привычке многие скажут, что .clearfix влепил — и все работает, но его использование не всегда оправдано, а иногда и невозможно, но каким-то образом нужно налаживать сопряжение блоков, что иногда вызывает трудности и увеличивает продолжительность верстки, а чаще всего отладки или добавления новых элементов в окружение.
Для начала рассмотрим, что же происходит с элементами и родительским элементом когда к ним добавляется свойство float: right и left. Рассмотрим небольшой пример:
<!-- Пример 1 - базовый -->
<style>
ul {
padding: 20px;
margin: 20px;
}
li {
float: left;
list-style: none;
margin-left: 5px;
border: 1px solid red;
}
</style>
<ul>
<li>первый</li>
<li>второй</li>
<li>третий</li>
</ul>
<p>Какой-то текст</p>
В примере LI имеют свойство float: left; и, как и следовало ожидать, выстраиваются в ряд один за другим и "Какой-то текст" прицепляется следом. Что же, это классическое поведение float. Но давайте посмотрим на родителя, ведь у нас еще есть UL: куда же делся он? Ему мы float не ставили, и по умолчанию это элемент блочный, почему же после него нет переноса?
А случилось следующее: для отображения float-элементов на странице браузер как бы "вырывает их из общего потока", помещает в нужное место, благодаря чему получается обтекание текстом и другими элементами. Именно для отключения обтекания было введено свойство clear, чтобы отключить его с нужной стороны выбранного блока.
Что же произойдет, если для родительского блока поставить clear: both;? Ровным счетом ничего, ведь, как я уже заметил ранее, float родителю мы не ставили и соответственно его ничто не обтекает, его как бы совсем нет, его содержимое было "вырвано из потока".
Давайте рассмотрим как с этим справится .clearfix:
<!-- Пример 2 - с применением .clearfix -->
<style>
.clearfix:after {
content: "";
display: table;
clear: both;
}
ul {
padding: 20px;
margin: 20px;
}
li {
float: left;
list-style: none;
margin-left: 5px;
border: 1px solid red;
}
</style>
<ul class="clearfix">
<li>первый</li>
<li>второй</li>
<li>третий</li>
</ul>
<p>Какой-то текст</p>
С задачей .clearfix справился. Как же он это делает? Он добавляет после выбранного элемента псевдоэлемент, который огибает все float элементы, расположенные ниже. Ниже именно потому, что родительский элемент в потоке пустой, его почти нет, и поэтому :after помещает элемент физически в самое начало, и браузеру приходится просчитывать, когда же все элементы закончат флоатиться, чтобы остановиться.
А вот вариант без использования .clearfix:
<!-- Пример 3 - без применения .clearfix -->
<style>
ul {
padding: 20px;
margin: 20px;
display: inline-block;
}
li {
float: left;
list-style: none;
margin-left: 5px;
border: 1px solid red;
}
</style>
<ul class="clearfix">
<li>первый</li>
<li>второй</li>
<li>третий</li>
</ul>
<p>Какой-то текст</p>
Свойство display: inline-block; для родительского элемента. Результат такой же, отличие лишь в том, что .clearfix оставляет родительский элемент блочным, либо таким, каким он был определен ранее. Как этим воспользоваться — решайте сами. И для классических решений эти способы практически равноценны.
Но если сам родительский элемент (и элементы внутри него) флоатится, а относительно него нужно расположить другие блоки, может возникнуть ситуация, когда .clearfix использовать нельзя. Родительский элемент будет занимать 0 размер (содержимое и он сам "вырваны из потока"). И чтобы спозиционировать в его окружении другие элементы, нужно будет либо прописывать фиксированную высоту (а она может быть непостоянной), либо "играться" с position: absolute; (что тоже не всегда можно предусмотреть непостоянством контента). В ряде случаев, добавляя в такие "узлы" на сайте дополнительный контент, может понадобиться пересмотреть всю концепцию верстки и переверстывать весь "узел".
Использование свойства display облегчит диагностику верстки средствами разработки (firebug или другими встроенными в браузеры средствами инспектирования), именно тогда, когда .clearfix применить не получается. Ведь если не сделать эту операцию, то родительский элемент найти инспектором не получится (если у него нет отступов), и под его содержимое не будет отведено место при рендэринге страницы (это хорошо заметно в примере 1 при инспектировании). display: inline-block; как раз и поможет избежать этих проблем.
Варианты верстки доступны по ссылке тут
Давайте еще рассмотрим вот такой вариант.
У clearfix — в родителя div.box не вошел внешний отступ(margin), который прописан для UL, а inline-block все воспринял как нужно все отступы на месте.
А для того, чтобы ширина inline-block стала как у block добавляем width: calc(100% — 80px) — не забываем что отступы внешние и внутренние нужно исключить из ширины.
Итого: в вашем распоряжении — более одного способа решения данной задачи. Хорошо, когда есть выбор, пользуйтесь на здоровье!
Комментарии (33)
ARad
10.08.2016 07:49+1inline-block все таки меняет верстру, для этого попробуйте закрасить ul желтым цветом. Также иногда полезно вставлять в нужное место пустой div с классом clearfix. Пример здесь https://jsfiddle.net/qzqfadnb/6/.
StrikeBack
10.08.2016 09:20+2display: inline-block не всегда хорош для решения этой задачи
https://jsfiddle.net/cs57yh3z/ по ссылке в примере у первого списка установлен display:inline-block, да его высота становится равна содержимому, но и ширина стала не 100%, так же если блоку установлен display: inline-block, то у этого блока появляется небольшой отступ в низу, который может подпортить верстку.
clearfix же решает эту задачу отлично.wanick
10.08.2016 09:25-1Читайте внимательнее в статье и написано что .clearfix решает эту задачу и при этом оставляет свойство display без изменений а inline-block, меняет его.
Sulin
10.08.2016 09:48-1Если используется display: inline-block; то нужно давать еще два свойства, width: 100%; и vertical-align: top;
Еще одной альтернативой есть метода overflow: hidden; у родителя, но стоит понимать что этот метод тоже не всегда подходит по понятным причинам.sashabeep
10.08.2016 10:15Только если после этого элемента будет перенос строки то со 100% width могут быть некоторые заморочки
SelenIT3
10.08.2016 10:41Фактически все решения проблемы «containing floats» делятся на 2 класса — собственно clearfix-ы (добавление (псевдо)блока с
clear:both
в конец родителя) и разные способы создания блочного контекста форматирования. Есть старенькая, но, видимо, местами еще актуальная статья с подробным разбором плюсов, минусов и ограничений каждого варианта (и попыткой найти новый вариант с минимумом ограничений:).
В теории, стандартным решением второго класса без побочных эффектов должно статьdisplay: block flow-root;
из CSS Display 3. На практике, боюсь, это пока нигде не работает:(. Но и сама необходимость всё реже благодаря тем же флексбоксам.
dpr
10.08.2016 10:41Вся суть сводится к тому, что необходимо создать новый поток элементов (контекст форматирования), в котором будут находится плавающие блоки.
Достичь этого можно разными способами. В частности — изменением свойства display на inline-block, table, inline-table, table-cell, table-caption, flex, inline-flex (гриды, вероятно, тоже будут создавать новые контексты, сам не пробовал); изменением overflow на auto, scroll, hidden; изменением float на left или right; изменением position на absolute или fixed.SelenIT3
10.08.2016 11:09+1С
display: *-flex
иdisplay: *-grid
есть нюанс, что они создают не блочный контекст форматирования, а свой собственный, с другими правилами размещения блоков (в частности, переопределяют поведение самих плавающих блоков). Решается дополнительной оберткой, но это уже далеко не так изящно… Строго говоря,display: *-table
тоже создает свой особый контекст (табличный), но в этом табличном контексте внутри*-table
автоматически достраиваются анонимные «обертки» сtable-row/table-cell
, и явная обертка не нужна.dpr
10.08.2016 11:39Всё верно. Собственно, каждый из этих способов (включая клирфикс) имеет свои нюансы, как положительные, так и отрицательные для решения конкретной задачи, о которых следует знать и применять по обстоятельствам. Одного солюшена для всех ситуаций, увы, пока нет. Хотя где-то в будущем уже маячат гриды, которые могут стать таким универсальным средством.
SelenIT3
10.08.2016 11:48Именно, я просто хотел уточнить, что не во всех контекстах форматирования плавающие блоки останутся плавающими:). А насчет плюсов и минусов — в статье, на которую я сослался чуть выше (одновременно с вашим комментом), есть неплохой наглядный пример разницы в действии:)
wanick
10.08.2016 11:03Давайте еще рассмотрим вот такой вариант.
https://jsfiddle.net/wanick/taojv46v/5/
специально добавил цвета чтобы видеть как clearfix и inline-block решают эту задачу,
У clearfix — родителя div.box не вошел внешний отступ(margin) который прописан для UL а inline-block все воспринял как нужно все отступы на месте.
Также добавил пример как для inline-block сделать width: calc(100% — 80px) — не забываем что отступы внешние и внутренние нужно исключить из ширины.Dil0ng
10.08.2016 12:00вроде как calc() плохо поддерживается во многих браузерах, в частности на телефонах. (Opera mini и UC Browser)
e_juke
10.08.2016 16:03В данном случае в втором примере (с .clearfix) поведение вполне корректное.
Не найдя внутри контейнера box каких-либо элементов, границ или padding'ов сверху и снизу, браузер рассчитал margin относительно ближайших элементов с границей: заголовка и строки «Какой-то текст» внизу. Таким образом отступы внутри box и не должны были появиться.
Если добавить, например, свойство border: 1px solid transparent для div.box, то отступы также будут видны, как и в последнем случае.
В случае же inline-block отступы всегда рассчитываются относительно родительского элемента, поэтому внутрь родителя и вошли внешние отступы ul.
fsanano
10.08.2016 16:03Есть третий способ. Родительскому элементу прописать:
. clearfix { overflow: hidden; }
Dreyk
10.08.2016 16:53+2Я ненавижу
inline-block
за его нетерпимость к пробелам между тегами. 1 пробел — и вся верстка летит к чертям. и приходится писать из-за этого отвратительный html типа
<ul> <li>asdasd</li><li> asdasd</li> </ul><ul> </ul>
mozyr
10.08.2016 17:23-1Достаточно просто указать для обертки font-size:0 и лишние пробелы уйдут.
А для дочерних элементов проставить размер шрифта заново.
vintage
А чем
display:flex
не угодил?FluffyMan
Судя по этой таблице flex криво поддерживает ie11.
symbix
На практике, единственная существенная проблема с min-height. Она отлично решается кормлением IE height вместо min-height CSS-хаком: в IE11 для флексбоксов height ведет себя как min-height. Прямо как в старые добрые времена с IE6, да-да.
sashabeep
Пресвятой Tridient… Я в шоке :)
symbix
У меня вообще есть подозрение, что в IE7 min-height починили хаком, а когда добавляли флексбоксы, забыли добавить еще одно условие в хак :)
Aingis
Увы, нет. В IE11 (и только в нём, в IE10 или Edge и Edge-как-IE11 нормально) есть адский баг, который проявляется при сочетании нескольких факторов: элемент с ограниченным размером (напр. max-width) больше чем flex-basis (то есть при flex-grow), так что есть свободное пространство для распределения, и выравнивание, отличающееся от flex-start (в том числе при разных вариантах margin: auto). В этом случае свободное место неправильно рассчитывается и элементы сдвигаются дальше чем должны.
Баг обойти нельзя, поэтому во flexbugs его не добавили (не спрашивайте меня в чём логика). Можно использовать flex-shrink вместо flex-grow, но это вынуждает задавать минимальный размер вроде min-width, и не даёт воспользоваться плюшками flex-basis с автоматическим минимальным размером в зависимости от содержимого.
symbix
А, такое было, я толком и не понял, в чем дело, просто обошел, переверстав чуть иначе.
Спасибо, после вашего комментария стало понятно.
Shannon
Не так уж и плохо, у ie10-11 есть некоторые «кривости» при поддержке flexbox, но они известны и собраны в одном месте рядом с простыми решениями
Список проблем с ie10-11 (и других браузеров) и их решения:
https://github.com/philipwalton/flexbugs#flexbugs
Плагин для postcss который сам исправит известные проблемы:
https://github.com/luisrudge/postcss-flexbugs-fixes
https://github.com/archana-s/postcss-flexbox
wanick
Согласен display:flex подходит, но по сравнению с inline-block — flex относительно новый элемент. По старой школе inline-block — привычнее, он работал еще в IE 5.5 и с тех пор его поведение не менялось, кросс-браузерность гарантирована… А по flex не все так однозначно, тут описания по поддержке, хоть спустя 5 лет после выхода гибрида можно уже и забыть о том, что кто-то там может не поддерживать — но тут чисто старая школа. :)