Улучшенный способ содержания плавающих элементов в IE с использованием CSS expression.

Перевод статьи:  Better float containment in IE.
Автор:  Nicolas Gallagher.

Исследования, ведущие к улучшению кроссбраузерной совместимости обеих методов содержания внутренних плавающих элементов — «clearfix» и «overflow:hidden». Цель – анализ соответствующих IE6 и IE7 багов.

В данной статье представлен новый хак (с определенными условиями), который может улучшить результат использования методов «clearfix» и новых способов включения плавающих элементов в контейнер, основанных на блочном контексте форматирования (New Block Formatting Context – NBFC), к примеру, с использованием свойства overflow:hidden. Этот хак является результатом сотрудничества Николаса Галлахера (то есть, меня) и Джонатана Нила Jonathan Neal.

Если же вы не знакомы с принципами, на которых основаны упоминаемые выше методы, то рекомендую вам прочесть первоисточник "Easy clearing" (2004), "Everything you know about clearfix is wrong"/«Все, что вам известно о Clearfix — неверно» (2010) и "Clearfix reloaded and overflow:hidden demystified"/«clearfix-reloaded и демистификация overflow:hidden» (2010).

Совместимые методы содержания плавающих элементов.

Соответствующий код представлен ниже и задокументирован на ресурсе GitHub gist. Если вы заметили в нем изъян или можете предложить его улучшение, то создайте свой форк, либо оставьте комментарий.

Micro clearfix hack (*здесь можно ознакомиться со статьей Николаса Галлахера о хаке Micro Clearfix). Поддержка в Firefox 3.5+, Safari 4+, Chrome, Opera 9+ и IE 6+:

.cf {
/* for IE 6/7 */
*zoom: expression(this.runtimeStyle.zoom="1", this.appendChild(document.createElement("br")).style.cssText="clear:both;font:0/0 serif");
/* в случае отключенной поддержке JS */
*zoom: 1;
}

.cf:before,
.cf:after {
content: "";
display: table;
}

.cf:after {
clear: both;
}

Overflow hack (NBFC). Поддержка в Firefox 2+, Safari 2+, Chrome, Opera 9+, IE 6+:

.nbfc {
overflow: hidden;
/* for IE 6/7 */
*zoom: expression(this.runtimeStyle.zoom="1", this.appendChild(document.createElement("br")).style.cssText="clear:both;font:0/0 serif");
/* в случае отключенной поддержке JS */
*zoom: 1;
}

На GitHub gist также можно найти другой вариант хака clearfix, который предназначен для современных браузеров (основан на работе Терри Кобленца/Thierry Koblentz). Он позволяет добиться лучшей визуальной совместимости (обходя крайние проблемные ситуации) даже в ранних версиях Firefox.

Единственным отличием предложенного здесь кода от уже существующих методов содержания плавающих элементов, является включение в его состав динамических CSS свойств (expression), при помощи которых создаются разрывы строк в IE6 и IE7. Мы с Джонатаном выяснили, что такой подход позволяет решить определенные проблемы, связанные с неоднозначностью визуализации, которые имеют место в этих двух версиях IE, а также в более поздних его версиях. Для начала позвольте объяснить вам, в чем заключаются эти различия визуализации и в каких ситуациях они проявляются.

IE 6/7 – содержание плавающих элементов в контейнере.

В браузере IE шестой и седьмой версии самым обычным и эффективным способом включения обтекаемых элементов в контейнер является установка для них свойства hasLayout. Инициация значения layout для элемента в IE 6/7 создает новый контекст блочного форматирования (NBFC). Тем не менее, определенные IE баги дают нам понять, что все предшествующие методы содержания плавающих объектов не решают проблему кроссбраузерной совместимости. Вот конкретные ситуации, которые возникают в IE 6/7 при создании NBFC:

  1. Верхние и нижние поля «не плавающих» дочерних элементов находятся в пределах элемента предка, для которого установлено значение layout. (Это же происходит и в других браузерах при создании NBFC.)
  2. Нижние поля любых плавающих, смещенных вправо (float:right) потомков содержаться в пределах контейнера. (Это же происходит при создании NBFC и в других браузерах.)
  3. Нижние поля любых плавающих, смещенных влево (float:left) дочерних элементов не будут включаться в рамки элемента предка. То есть значения нижних полей этих элементов не будут влиять на высоту предка, а будут игнорироваться, не оказывая также никакого эффекта и за пределами контейнера (баг IE 6/7).
  4. При этом, если в IE 6 правый край области, образуемой полями плавающего, смещенного влево дочернего элемента находится в пределах 2 пикселей от левого края области содержания (внутреннего блока контента) контейнера с NBFC, то нижнее поле дочернего элемента появляется и находится в пределах родительского элемента контейнера (баг IE 6).
  5. Возможно появление пробела в нижней части содержащего плавающие элементы контейнера, что в некоторых случаях нежелательно (IE 6/7 баг).

Между IE 6/7 и другими браузерами, в прочем, как и между самими IE 6 и IE 7 существует определенная несовместимость. Я обратил внимание на такое поведение IE 6/7 благодаря комментарию Метью Лейна (Matthew Lein), к тому же этот вопрос был упомянут в еще одном комментарии от "Suzy" на сайте Perishable Press.

Эффект усечения нижнего поля у плавающих, смещенных влево элементов, имеющий место в IE 6/7, не рассматривается во многих случаях обсуждения и демонстрации технологий содержания плавающих объектов. Применение же, IE-вендорного динамического CSS свойства expression позволяет справиться с этим багом.

CSS expression

Включение нежелательного элемента <br style="clear:both"> в нижней части контейнера, также как и создание NBFC, исключало проявление всех упомянутых выше случаев несовместимости в IE 6/7. То есть использование данных приемов позволяет избежать «схлопывания» верхних и нижних полей у дочерних элементов в этих браузерах.

Изображение.

Джонатан Нил (Jonathan Neal) внес предложение: исключительно для IE 6/7 включать отменяющий обтекание элемента разрыв строки с использованием функционала динамических свойств expression. В результате множества итераций, тестов и размышлений, выбор был остановлен на использовании CSS-выражения, которое вычисляется один раз, только при первичном назначении стилей форматируемому элементу.

*zoom: expression(this.runtimeStyle.zoom="1", this.appendChild(document.createElement("br")).style.cssText="clear:both;font:0/0 serif");

Данное выражение применяется к свойству zoom, которое уже с успехом используется для включения плавающих объектов в элемент контейнер в браузерах IE 6/7. К тому же, в выражении употребляется объект runtimeStyle, что гарантирует однократное вычисление выражения. Наличие установок font: 0/0 serif позволяет избежать случайного появления пробела в нижней части содержащего контейнера. А звездочка * является хаком, гарантирующим, что это правило будет выполнено только в IE 6 и IE 7.

Пользы от того, что IE 6 и IE 7 парсят практически любую строку, используемую в качестве CSS свойства, никакой. В предыдущих попытках применялись совершенно фиктивные свойства -ms-inject или -ie-x с целью эксплуатации такого поведения IE:

*-ie-x: expression(this.x||(this.innerHTML+='<br\ style="clear:both;font:0/0">',this.x=1));

Тем не менее, это выражение вычисляется многократно. (*При срабатывании любого обработчика события или запуска других JavaScript-ов, присутствующих в документе.) Сергей Чикуёнок обратил также внимание и на то, что использование метода innerHTML нарушает структуру уже существующих в документе HTML элементов, а соответственно может удалить содержащиеся в них обработчики событий (*и не только обработчики). Но применяя document.createElement и appendChild, вы можете вставить новый элемент без негативных последствий, типа удаления всех обработчиков событий у других дочерних элементов.

Обработка плавающих объектов в более современных браузерах.

Существует два распространенных метода включения плавающих элементов в контейнер в современных браузерах. Создание нового блочного контекста форматирования (как это делается в IE 6/7 при задействовании свойства hasLayout) или использование одного из вариантов хака Clearfix.

Изображение.

Создание NBFC позволяет включать в элемент обтекаемые с любой стороны дочерние объекты и предотвращает объединение верхних и нижних полей у не «плавающих» дочерних элементов. А в том случае, если этот подход используется совместно с усовершенствованным методом содержания плавающих объектов для IE 6/7, то это создает универсальный кроссбраузерный способ обработки плавающих блоков в рамках элемента контейнера.

Другой же метод, известный как clearfix, традиционно использует единственный псевдо-элемент :after для отмены обтекания плавающих объектов, по принципу, схожему с тем, на котором основан рассмотренный нами ранее метод, использующий «очищающий» структурный HTML элемент разрыва строки. Однако, для предотвращения «схлопывания» верхних полей у «не плавающих» элементов с полями блока контейнера, содержащего плавающие объекты, вам нужно использовать второй псевдо-элемент — :before. Именно этот подход применяется в хаке clearfix reloaded Терри Кобленца (Thierry Koblentz). Для современных браузеров также подойдет хак micro clearfix.

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

Возможные проблемы.

Предусмотренное данным подходом применение CSS-выражений для внесения изменений в DOM структуру документа приводит к проблемам, связанным с некоторыми расхождениями реализации DOM в IE 6/7 и других браузерах. Это касается случаев манипуляции DOM структурой документа при помощи JavaScript, и одновременным использованием селекторов типа :last-child в CSS или добавлением новых дочерних элементов.

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

* Примечание переводчика.

Добавить комментарий

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