Главная » Полезные статьи » HTML-верстка » Новая альтернатива clearfix-у и overflow:hidden
Распечатать статью

Новая альтернатива clearfix-у и overflow:hidden

Сегодня я проснулся с каким-то странным чувством. Мне как будто казалось, что что-то должно произойти. Я вошёл в скайп и не ошибся! Меня уже поджидал Илья Стрельцын (@SelenIT2) с неожиданным решением одной известной задачи, связанной с очисткой потока.

Я полагаю, многие верстальщики уже догадались – о чём идёт речь, а если нет, то перед тем, как переходить к решению Ильи, давайте немного освежим память и вкратце рассмотрим несколько известных методов, а так же их достоинства и недостатки.

Я решил, что все способы следует рассматривать сразу на маленьком, но боевом примере.

Условие задачи

Есть две колонки. Левая с float:left имеет фиксированные ширину и высоту. Нужно, чтобы правая тянулась на всю оставшуюся ширину. При этом необходимо, чтобы из той же правой колонки не «вываливались» margin-ы элементов, а элементы с float: left или right не схлопывали высоту контейнера, и чтобы края колонки не обрезали элементы, которые из неё вылезают.

В общем, в результате должно получиться что-то нечто похожее на следующий пример:

Решения

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

Перед тем, как переходить к первому варианту, предлагаю сразу посмотреть структуру HTML и часть CSS, которые во всех примерах будут абсолютно одинаковыми. Единственное что будет меняться в HTML — это классы у правой колонки (в зависимости от способа), а в CSS только лишь та часть, которая относится к методу.

<div class="left">
        <h2>Левый float</h2>
</div>
<div class="clearfix">
        <div class="date">12.05.2012</div>
        <h2>Заголовок</h2>
        <p>Ниже идёт картинка с float:left</p>
        <img src="img.jpg" class="float-left">
        <p class="clear-both">А у этого абзаца стоит clear:both;</p>
        <div class="absolute">Absolute</div>
</div>
/* Общие стили */
.left {
        float: left;
        width: 200px;
        background: #FC6;
        height: 200px;
        position: relative;
        z-index: 1;
}

h2 { margin-top: 10px;}
.float-left { float: left;}
.clear-both {
        font-size: 15px;
        clear: both;
        background: #F99;
}
.date {
        font-size: 20px;
        float: right;
        background: #FC0;
        padding: 2px 5px;
        margin: -10px -5px 0 0;
}
.absolute {
        position: absolute;
        bottom: -25px;
        right: 10px;
        width: 50px;
        height: 50px;
        background: white;
        border: 2px solid black;
}

clearfix

Для первого эксперимента возьмём один из самых популярных clearfix-ов, который в своё время доработал Chris Coyier, отказавшись от ненужного свойства font-size, в связи с пустым свойством content. Выглядит он так:

.clearfix:after {
        visibility: hidden;
        display: block;
        content: "";
        clear: both;
        height: 0;
        }
* html .clearfix             { zoom: 1; } /* IE6 */
*:first-child+html .clearfix { zoom: 1; } /* IE7 */

Я применил этот код к правой колонке, добавив ещё несколько свойств чисто для оформления. И вот что у нас получилось:

Как виндно по рисунку, из плюсов можно выделить только то, что благодаря clearfix-у правый нижний блок с position: absolute остался целым и невредимым и его вылезающая из колонки часть не образелась.

Ну, а в остальном, к сожалению, одни минусы. Их настолько много, что я даже сделал список:

  • Верхние margin-ы у заголовка выпали из контейнера.
  • Левый padding в контейнере провалился под левую колонку и больше не является отступом между элементами в правой колонке и левой с float: left. Оно и понятно, ведь clearfix не создаёт свой собственный контекст, поэтому блочная часть правой колонки фактически оказывается под левой, обтекая её своими инлайновыми боксами.
  • Ну и самое печальное тут то, что последний абзац с clear:both оказался под левой колонкой, растягивая собой правую по высоте. Это опять же из-за того, что левая колонка и плавающая картинка в правой колонке остались в одном и том же контексте форматирования, поэтому clear реагирует и на то, и на другое.

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

overflow: hidden или auto

Ещё один, более достойный и простой способ, на мой взгляд, заключается в том, чтобы повесить на контейнер свойство overflow со значениями hidden или auto, благодаря которым мы создадим новый контекст форматирования и тем самым сможем изолировать наш блок – колонку от внешнего контекста.

Во-первых, в самой структуре мы лишь поменяем класс у правой колонки с class=»clearfix» на class=»overflow», а во-вторых, изменим наш CSS в пользу текущего метода.

/* метод с overflow */
.overflow {
        padding: 0 10px;
        background: #E76D13;
        position: relative;

        /* overflow */
        overflow: hidden;
}

* html .overflow { zoom: 1; } /* IE6 */
*:first-child+html .overflow { zoom: 1; } /* IE7 */

И вот, что у нас вышло:

На вид этот способ явно лучше предыдущего, за исключением того, что вылезающие за края элементы – обрезаются. Дело в том, что overflow: hidden устроен так, что выходящие за края блока элементы – попросту обрезаются, а со значением auto вообще появляется скроллинг. Этот нюанс порой доставляет массу неудобств, заставляя отказываться от этого метода в пользу других.

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

display:table

В эпоху быстро-уходящих на покой IE6-7 актуальными становятся свойства и значения, которые не имели поодержки в этих недобраузерах. И одна из таких «парочек» имеет название display: table и так же может являться ещё одним методом для решения нашей задачи. display: table, как и overflow: hidden вешается на контейнер, но работает немного иначе.

По традиции причешем наш код…

/* метод с display: table */
.table  {
        padding: 0 10px;
        background: #E76D13;
        position: relative;

        /* display: table */
        display: table;
}

* html .table  { zoom: 1; } /* IE6 */
*:first-child+html .table  { zoom: 1; } /* IE7 */

И посмотрим результат:

Так же, как и overflow: hidden display: table создаёт свой собственный контекст форматирования, изолирует контейнер, и мало того, в отличие от overflow: hidden, избегает проблем с обрезанием вылезающих элементов.

Но, проблема всё же есть, и она кроется в том, что элементы с этим свойством (в нашем случае – это правая колонка) ужимаются по содержимому и поэтому не растягивают контейнер на всю оставшуюся ширину.

Так что, к сожалению, это решение нам тоже не подходит, поэтому пора переходить к самому вкусному!

Метод Ильи Стрельцына

Вот, наконец, мы и добрались до самого главного способа, который основан на предыдущем варианте с display:table, но имеет очень важное дополнение, которое и делает этот метод полностью рабочим.

Для начала сразу же приведу код, а уже после просмотра результата объясню в чём вся соль.

/* метод Ильи Стрельцына */
.table  {
        padding: 0 10px;
        background: #E76D13;
        position: relative;

        /* display: table */
        display: table;
}
/* Очень важное дополнение! */
.table:after {
        content: '. .';
        display: block;
        word-spacing: 99in;
        height: 0;
        overflow: hidden;

        /* Лекарство бага с оступом в Opera */
        font-size: 0.05em;
        line-height: 0.05em;
}

И, соответственно, результат:

На изображении можно увидеть, что все перечисленные в задаче пункты – выполнены и задача решена полностью. Правая колонка тянется на оставшуюся ширину, margin-ы элементов не вываливаются наружу, высота контейнера не схлопывается по высоте, и даже выпирающие элементы не обрезаются! В чём же подвох?

На самом деле в решении этой задачи нам помогает тот же трюк с псевдоэлементом, который помогал выравнивать блоки по резиновой сетке в этой статье. Весь приём заключается в двух свойствах и их значениях – это content: ‘. .'; и word-spacing: 99in;. Обратите внимание на две текстовые точки в свойстве content и на значение у word-spacing (99in), которое можно пересчитать в 9504px (с эстетической точки зрения 99in выглядят всё же красивее=)). Но давайте разберёмся более детально.

В общем, по спецификации, для таких вещей, как таблицы, ширина считается по алгоритму shrink-to-fit. Кратко объяснить его суть можно так. Вначале браузер «спрашивает» у контента, сколько бы ему хотелось иметь ширины, чтоб вольготно раскинуться в одну строку, не ломая строки переносами. Если ширина, «запрошенная» контентом, меньше доступной ширины контейнера — именно эта «запрошенная» ширина назначается нашему элементу. Если же нет — назначается такая ширина, чтобы элемент вплотную вписался в доступную ширину контейнера, а контенту волей-неволей приходится втискиваться в эту ширину, перенося строки.

В нашем случае текст псевдоэлемента (те самые 2 точки с пробелом между ними) «запрашивает» почти 10 тыс. пикселей — обычная ширина двух точек с пробелом плюс 9504 пикселей, на которые этот пробел увеличен благодаря word-spacing‘у. То есть в любых реальных условиях этот контент никогда не сможет уместиться в одну строку, и браузеру всегда придется считать ширину нашей таблицы по второму варианту — по контейнеру. А ведь именно этого мы и добивались!

Заключение

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

p.s. Хочется сказать отдельное спасибо Александру Егереву (aka alexriz) за решение, которое помогло исправить неприятный баг в браузере Opera, связанный с непонятным нижним отступом (см. комментарии). Добавил решение в статью.

Источник:  css-live.ru
Вы можете оставить комментарий, или обратную ссылку на Ваш сайт.

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

Похожие статьи