Альтернатива для .clearfix

  • Tutorial

.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) — не забываем что отступы внешние и внутренние нужно исключить из ширины.


Итого: в вашем распоряжении — более одного способа решения данной задачи. Хорошо, когда есть выбор, пользуйтесь на здоровье!

Share post

Similar posts

AdBlock has stolen the banner, but banners are not teeth — they will be back

More
Ads

Comments 33

    +3

    А чем display:flex не угодил?

      0
      Судя по этой таблице flex криво поддерживает ie11.
        +5
        На практике, единственная существенная проблема с min-height. Она отлично решается кормлением IE height вместо min-height CSS-хаком: в IE11 для флексбоксов height ведет себя как min-height. Прямо как в старые добрые времена с IE6, да-да.
          0
          Пресвятой Tridient… Я в шоке :)
            0
            У меня вообще есть подозрение, что в IE7 min-height починили хаком, а когда добавляли флексбоксы, забыли добавить еще одно условие в хак :)
            +1
            Увы, нет. В IE11 (и только в нём, в IE10 или Edge и Edge-как-IE11 нормально) есть адский баг, который проявляется при сочетании нескольких факторов: элемент с ограниченным размером (напр. max-width) больше чем flex-basis (то есть при flex-grow), так что есть свободное пространство для распределения, и выравнивание, отличающееся от flex-start (в том числе при разных вариантах margin: auto). В этом случае свободное место неправильно рассчитывается и элементы сдвигаются дальше чем должны.

            Баг обойти нельзя, поэтому во flexbugs его не добавили (не спрашивайте меня в чём логика). Можно использовать flex-shrink вместо flex-grow, но это вынуждает задавать минимальный размер вроде min-width, и не даёт воспользоваться плюшками flex-basis с автоматическим минимальным размером в зависимости от содержимого.
              +1
              А, такое было, я толком и не понял, в чем дело, просто обошел, переверстав чуть иначе.
              Спасибо, после вашего комментария стало понятно.
            0
            Не так уж и плохо, у 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
            –2
            Согласен display:flex подходит, но по сравнению с inline-blockflex относительно новый элемент. По старой школе inline-block — привычнее, он работал еще в IE 5.5 и с тех пор его поведение не менялось, кросс-браузерность гарантирована… А по flex не все так однозначно, тут описания по поддержке, хоть спустя 5 лет после выхода гибрида можно уже и забыть о том, что кто-то там может не поддерживать — но тут чисто старая школа. :)
            +1

            inline-block все таки меняет верстру, для этого попробуйте закрасить ul желтым цветом. Также иногда полезно вставлять в нужное место пустой div с классом clearfix. Пример здесь https://jsfiddle.net/qzqfadnb/6/.

              +2
              display: inline-block не всегда хорош для решения этой задачи
              https://jsfiddle.net/cs57yh3z/ по ссылке в примере у первого списка установлен display:inline-block, да его высота становится равна содержимому, но и ширина стала не 100%, так же если блоку установлен display: inline-block, то у этого блока появляется небольшой отступ в низу, который может подпортить верстку.

              clearfix же решает эту задачу отлично.
                –1
                Читайте внимательнее в статье и написано что .clearfix решает эту задачу и при этом оставляет свойство display без изменений а inline-block, меняет его.
              • UFO just landed and posted this here
                  0
                  Только если после этого элемента будет перенос строки то со 100% width могут быть некоторые заморочки
                  0
                  Он добавляет после выбранного элемента псевдоэлемент, который огибает все float элементы, расположенные ниже.

                  Небольшая поправочка, если позволите — добавляет не после, а внутри элемента с присвоенным классом.
                    0
                    Внутри в конец, если быть совсем точным.
                    0
                    Фактически все решения проблемы «containing floats» делятся на 2 класса — собственно clearfix-ы (добавление (псевдо)блока с clear:both в конец родителя) и разные способы создания блочного контекста форматирования. Есть старенькая, но, видимо, местами еще актуальная статья с подробным разбором плюсов, минусов и ограничений каждого варианта (и попыткой найти новый вариант с минимумом ограничений:).

                    В теории, стандартным решением второго класса без побочных эффектов должно стать display: block flow-root; из CSS Display 3. На практике, боюсь, это пока нигде не работает:(. Но и сама необходимость всё реже благодаря тем же флексбоксам.
                      0
                      Вся суть сводится к тому, что необходимо создать новый поток элементов (контекст форматирования), в котором будут находится плавающие блоки.
                      Достичь этого можно разными способами. В частности — изменением свойства display на inline-block, table, inline-table, table-cell, table-caption, flex, inline-flex (гриды, вероятно, тоже будут создавать новые контексты, сам не пробовал); изменением overflow на auto, scroll, hidden; изменением float на left или right; изменением position на absolute или fixed.
                        +1
                        С display: *-flex и display: *-grid есть нюанс, что они создают не блочный контекст форматирования, а свой собственный, с другими правилами размещения блоков (в частности, переопределяют поведение самих плавающих блоков). Решается дополнительной оберткой, но это уже далеко не так изящно… Строго говоря, display: *-table тоже создает свой особый контекст (табличный), но в этом табличном контексте внутри *-table автоматически достраиваются анонимные «обертки» с table-row/table-cell, и явная обертка не нужна.
                          0
                          Всё верно. Собственно, каждый из этих способов (включая клирфикс) имеет свои нюансы, как положительные, так и отрицательные для решения конкретной задачи, о которых следует знать и применять по обстоятельствам. Одного солюшена для всех ситуаций, увы, пока нет. Хотя где-то в будущем уже маячат гриды, которые могут стать таким универсальным средством.
                            0
                            Именно, я просто хотел уточнить, что не во всех контекстах форматирования плавающие блоки останутся плавающими:). А насчет плюсов и минусов — в статье, на которую я сослался чуть выше (одновременно с вашим комментом), есть неплохой наглядный пример разницы в действии:)
                        +1
                        Когда уже даже намек на клирфикс пропадет (
                          0
                          Давайте еще рассмотрим вот такой вариант.
                          https://jsfiddle.net/wanick/taojv46v/5/

                          специально добавил цвета чтобы видеть как clearfix и inline-block решают эту задачу,
                          У clearfix — родителя div.box не вошел внешний отступ(margin) который прописан для UL а inline-block все воспринял как нужно все отступы на месте.

                          Также добавил пример как для inline-block сделать width: calc(100% — 80px) — не забываем что отступы внешние и внутренние нужно исключить из ширины.
                            0
                            вроде как calc() плохо поддерживается во многих браузерах, в частности на телефонах. (Opera mini и UC Browser)
                              0
                              Соглашусь с вами, calc — не самый удачный пример, но это лишь демонстрационный пример, который показывает что ширину выставлять нужно «не забывая» про отступы.
                              0
                              В данном случае в втором примере (с .clearfix) поведение вполне корректное.
                              Не найдя внутри контейнера box каких-либо элементов, границ или padding'ов сверху и снизу, браузер рассчитал margin относительно ближайших элементов с границей: заголовка и строки «Какой-то текст» внизу. Таким образом отступы внутри box и не должны были появиться.
                              Если добавить, например, свойство border: 1px solid transparent для div.box, то отступы также будут видны, как и в последнем случае.

                              В случае же inline-block отступы всегда рассчитываются относительно родительского элемента, поэтому внутрь родителя и вошли внешние отступы ul.
                              0
                              Есть третий способ. Родительскому элементу прописать:
                              . clearfix { overflow: hidden; }
                                +2

                                Я ненавижу inline-block за его нетерпимость к пробелам между тегами. 1 пробел — и вся верстка летит к чертям. и приходится писать из-за этого отвратительный html типа


                                <ul>
                                  <li>asdasd</li><li>
                                       asdasd</li>
                                </ul><ul>
                                </ul>
                                  –1
                                  Достаточно просто указать для обертки font-size:0 и лишние пробелы уйдут.
                                  А для дочерних элементов проставить размер шрифта заново.
                                    +2

                                    насколько я помню, с этим тоже были какие-то проблемы, сейчас уже не вспомню...

                                      0
                                      В андроид-браузерах, как минимум.
                                    0
                                    А можно писать красивый и валидный(подходит только для li)
                                    <ul><li>asdasd
                                      <li>asdasd
                                    </ul>
                                    

                                    Впрочем, вариантов решения этой проблемы масса.
                                      0

                                      вариантов масса, но, как видите, ни один не подходит на 100% поэтому и ненависть =)

                                  Only users with full accounts can post comments. Log in, please.