Изучаем наличие layout

Ниже представлен первый перевод статьи "On having Layout" на русский язык. Статья не является окончательной. Этот перевод отражает 8 версию от 19.06.2007.

Введение

Множество несоответствий (стандартам) Internet Explorer’а при визуализации
веб-страниц может быть устранено путем присвоения конкретным элементам свойства
layout. John Gallant и Holly Bergevin называют эти несоответствия
«пространственными ошибками», подразумевая, что они часто могут быть исправлены,
если задать элементу ширину или высоту. Это ведет к справедливому вопросу: каким
образом layout может менять визуализацию одного элемента и совместное
отображение нескольких? Это замечательный вопрос, но ответить на него совсем не
так просто. В данной статье авторы фокусируются на некоторых аспектам этой
нетривиальной проблемы. Также в статье приводятся ссылки на примеры и дальнейшее
обсуждение.

hasLayout: определение

Layout является исключительно концепцией IE/Win, которая определяет,
как будет ограничено и визуализировано внутреннее содержание элементов, как
элементы будут взаимодействовать и влиять друг на друга, реагировать на и
передавать события, вызванные пользователем или приложением.

Это качество в одностороннем порядке может быть вызвано некоторыми свойствами
CSS. Некоторые HTML элементы обладают им по умолчанию.

Разработчики Microsoft решили, что элементы должны иметь возможность получать
это «свойство» (в терминах объектно-ориентированного подхода), и они назвали его
hasLayout. Это свойство становится true, если
применяется такой метод визуализации.

Терминология

Мы говорим, что элемент «приобретает layout» или, что элемент «имеет
layout», когда для него Microsoft’овское свойство

hasLayout
становится true. «Элементом с layout»
может быть любой элемент, который имеет layout по умолчанию либо
получил его в результате выставления некоторых соответствующих CSS-свойств.

В «не-layout» элементах свойство hasLayout не
выставлено, например, чистый div Без заданных размеров может быть
«не-layout родителем».

Под вопросом находится присвоение layout элементу, у которого его по
умолчанию нет, с помощью CSS-свойств, которые вызывают hasLayout = true.
Смотрите также
элементы, у которых есть layout по умолчанию,
и
CSS-свойства, его
вызывающие
. Единственным способом выставить hasLayout = false
является удаление или сброс первоначального CSS-свойства, которое вызвало
hasLayout = true
.

С чем приходится иметь дело

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

Следствием того, что у элемента есть или нет layout, может быть:

  • Распространенные ошибки IE при отображении «плавающих» блоков;
  • Различное поведение самих блоков при одинаковых базовых свойствах;
  • «Схлопывание» полей между родителем и его потомками;
  • Различные проблемы с созданием списков;
  • Разное позиционирование фоновых картинок;
  • Различия между браузерами при использовании скриптов.

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

Откуда появляется layout

В отличие от стандартных свойств или специфических CSS-свойств, доступных в
различных браузерах, layout не может быть присвоен напрямую
через CSS-объявления
. Другими словами, не существует никакого «layout-свойства».
Определенные элементы автоматически «имеют layout«, и оно может быть
незаметно добавлено при различных CSS-объявлениях.

Элементы, у которых по умолчанию есть layout

По-видимому, layout есть по умолчанию у следующих элементов.

  • <html>, <body>
  • <table>, <tr>, <th>, <td>
  • <img>
  • <hr>
  • <input>, <button>, <select>,
    <textarea>, <fieldset>, <legend>
  • <iframe>, <embed>, <object>,
    <applet>
  • <marquee>

Свойства

Следующие заданные пары CSS-свойств/значений позволяют элементу получить
layout
.

  • position: absolute.Назначается блоку, в него вложенному, что является причиной некоторых
    проблем.
  • float: left|rightУ модели «плавающих» элементов присутствует множество хаков (quirks),
    связанных с некоторыми аспектами layout-элемента.
  • display: inline-blockИногда помогает, когда элемент находится на уровне строки, и ему требуется
    layout. Добавление layout, по-видимому, единственный
    реальный эффект этого свойства. Само по себе «поведение в качестве строчного
    блока» (inline-block) может быть получено в IE, но несколько
    независимо:

    IE/Win: строчный блок и hasLayout
    .
  • width: любое значение, отличное от autoОчень часто используется в качестве неявного исправления, даже чаще, чем
    hasLayout успевает испортить ситуацию.
  • height: любое значение, отличное от autoheight: 1% используется как Holly Hack.
  • zoom: любое значение, отличное от normal (MSDN)Исключительно MS-свойство, не стандартно. zoom: 1 может быть
    использовано для отладки.
  • writing-mode: tb-rl (MSDN)Исключительно MS-свойство, не стандартно.

В IE7 переполнение (overflow) вызывает также присвоения layout.

  • overflow: hidden|scroll|autoЭто свойство не применяется в предыдущих версиях, пока layout не
    будет добавлен к блоку другими методами.
  • overflow-x|-y: hidden|scroll|autoЯвляясь частью модуля блочной модели CSS3, overflow-x и
    -y
    пока еще не достаточно широко реализованы. Они не вызывали
    свойство hasLayout в предыдущих версиях IE.

В IE7 появились новые действующие лица, регулирующие hasLayout.
В контексте hasLayout минимальные/максимальные свойства действуют
аналогично ширине и высоте, и, по-видимому, так же работает фиксированное и
абсолютное позиционирование.

  • position: fixed./.
  • min-width: любое значениеДаже выставление значения в 0 присваивает элементу layout.
  • max-width: любое значение отличное от 'none'./.
  • min-height: любое значениеДаже значение, равное 0, выставляет hasLayout = true.
  • max-height: любое значение отличное от 'none'./.

Информация получена с помощью IE Developer Toolbar и предварительного
тестирования.

Замечания по поводу линейных (inline) элементов

Для линейных элементов (либо линейных по умолчанию, как span,
или при назначении им display: inline)

  • width и height вызывают hasLayout
    в IE5.x и IE6 или более новых только в режиме «quirks». Начиная с IE6, когда
    браузер находится в режиме «стандартной совместимости», линейные элементы
    игнорируют свойства width и height, и выставление
    свойств width или height не заставляет элемент
    приобрести layout.
  • zoom всегда вызывает hasLayout, но оно не
    поддерживается в IE5.0.

Элементы, у который есть layout и display: inline ведут
себя именно так, как предписано это стандартами для линейных блоков (inline-block):
они располагаются горизонтально, как слова в строке или абзаце, чувствительны к
вертикальному выравниванию и применяют некоторые методы «ужатия» (shrink-wrapping)
к собственному содержимому. Как только линейные элементы получают layout,
они начинают вести себя как линейные блоки. В этом и заключается объяснение того
факта, что в IE/Win линейные элементы могут содержать блочные, и при этом
возникает меньше проблем, чем в других браузерах, в которых элементы с
display: inline
остаются линейными.

Сбрасываем hasLayout

Если выставить следующие свойства в их значения по умолчанию с помощью
отдельного правила, это сбросит (или отменит) hasLayout, если не
останется других свойств, его выставляющих:

  • width, heightauto);
  • max-width, max-heightnone) (в
    IE7);
  • positionstatic);
  • floatnone);
  • overflowvisible) (в IE7);
  • zoomnormal);
  • writing-mode (из tb-rl в lr-tb).

Разработчикам стоит с осмотрительностью использовать сброс этих свойств.
Рассмотрим какое-нибудь меню: изменение статуса hasLayout у
a:hover
, умышленно или нет, приведет к неожиданному отображению (или
нестабильности IE6 при совместном динамическом использовании с position:
relative
). Прим.: более подробно с этим аспектом можно ознакомиться в
разделе списки.

Отличается и свойство display: если inline-block
выставляет haslayout = true, этот флаг позже не сбрасывается в
false при переписывании этого значения с помощью

block
или

inline
в другом наборе правил.

Выставление свойств min-width, min-height в их
значение по умолчанию, которое равно 0, по-прежнему присваивает
элементу hasLayout, но IE7 воспринимает для таких целей
нестандартное значение auto, которое и сбрасывает hasLayout.

Скриптовое свойство hasLayout

Мы предпочитаем называть hasLayout «скриптовым свойством», чтобы
отличать его от свойств CSS, с которыми мы имеем дело.

Нет никакого способа напрямую выставить или сбросить это скриптовое свойство
hasLayout.


Свойство hasLayout
может быть использовано для того, чтобы
проверить, есть ли у элемента layout или нет. Например, если у него
id равно eid, то простая запись в адресной строке
IE5.5+ выведет его состояние: javascript:
alert(eid.currentStyle.hasLayout)
.


IE Developer Toolbar
позволяет «в живую» проверить текущие стили у элемента:
когда hasLayout выставлено в true, то его значение выводится как
-1. Вручную редактируя атрибуты узла, для отладки можно выставить
zoom (CSS) в 1, чтобы сработало установление
hasLayout
.

Другим важным моментом является влияние layout на скрипты. Свойства
clientWidth/clientHeight возвращают нуль для элементов без
layout
. Это может вводить в недоумение начинающих JavaScript-программистов,
потому что такое поведение отличается от Mozilla-подобных браузеров. Можно
использовать этот факт для определения понятия layout для IE5.0: если у
элемента clientWidth является нулем, то у него нет layout.
Прим. более подробно о толковании свойства hasLayout можно
прочитать в разделе
Заглядываем
внутрь

CSS-хаки

Следующие хаки устанавливают свойство hasLayout, они были
проверены в IE7 и более ранних версиях.

John Gallant и Holly Bergevin опубликовали Holly hack в 2003:


/* \*/
   * html .gainlayout { height: 1%; }
/* */
  • Обеспечивает layout в IE5–6 для любого элемента, за исключением
    линейных в IE6 в стандартном режиме.
  • Работает, в общем случае, хорошо за исключением тех случаев, когда
    height:0
    или 1px является более стабильным решением.
  • Не совместим с overflow: hidden, кроме IE6 в стандартном
    режиме (в нем height: 1% приводится к height: auto,
    если у родительского элемента не задана высота).
  • Не имеет никакого эффекта в IE7 в стандартном режиме, в нем * html
    не соответствует никакому элементу.

Чтобы назначить layout в IE6 и более ранних версиях, мы можем использовать хак с подчеркиванием:


.gainlayout { _height: 0; }

И чтобы назначить layout для IE7, можно воспользоваться свойством min-height:


.gainlayout { min-height: 0; }

Альтернативным путем, и, возможно, выдержавшим проверку временем, является использованием условных комментариев:


&lt;!--[if lte IE 6]&gt;
   &lt;style&gt;
   .gainlayout { height: 1px; }
   &lt;/style&gt;
   &lt;![endif]--&gt;

   &lt;!--[if IE 7]&gt;
   &lt;style&gt;
   .gainlayout { zoom: 1; }
   &lt;/style&gt;
   &lt;![endif]--&gt;

Еще одним безопасным и изящным решением будет использование внешней таблицы
стилей, вызываемой из условных комментариев, для каких бы то ни было
исправлений, в которых нуждается IE-Win:

   <link rel="stylesheet" href="allbrowsers.css" type="text/css" />

   <!--[if lte IE 7]>
   <link rel="stylesheet" href="iefix.css" type="text/css" />
   <![endif]-->

Для IE6 и более ранних версий стоит всегда использовать
height (если мы хотим обеспечить поддержку IE5.0, у нас будет не
такой большой выбор), хотя это свойство и вызывает конфликты с чем-то другим (overflow:
hidden
). Что касается значения, то 1%, 1px,
0 будет более или менее равноправны, но 1% может (хотя
и очень редко) вызывать некоторые

проблемы
.

height не может использоваться для линейных элементов в
стандартном режиме, и этого свойства стоит избегать в IE7 (или использовать с
крайней осторожностью: только значения в процентах, и только при отсутствии у
родительского элемента заданной высоты). В таких случаях рекомендуется
использовать display: inline-block или zoom: 1.

Мы наблюдали некоторое количество безуспешных попыток применить так
называемые «Holy hacks» к плавающим элементам или к элементам с заданной
шириной. Запомните: целью данного хака является не задание элементу высоты, но
вызов hasLayout = true.

Не присваивайте layout всему подряд: * {_height: 1px;}.
В таких количествах layout вместо лечебного воздействия способен убить
вашу верстку на корню: отображение страницы поменяется фундаментальным образом.

Управление хаками

Как показал релиз IE7, невозможно предсказать, будут ли следующие версии IE
по-прежнему нуждаться в hasLayout для исправления некоторых ошибок
и как они будут реагировать на фильтры, которые используются на текущий момент.
В этом свете рекомендуется использовать исключительно MS-свойство zoom
и(ли) условные комментарии.

   <!--[if lt IE 7]><style>
   /* style for IE6 + IE5.5 + IE5.0 */
   .gainlayout { height: 0; }
   </style><![endif]-->

   <!--[if IE 7]><style>
   .gainlayout { zoom: 1; }
   </style><![endif]-->
  • zoom: 1; присваивает layout в IE5.5+ любому
    элементу (включая линейные), но не имеет никакого эффекта в IE5.0
  • Не известно побочных эффектов (хотя линейные элементы ведут себя как
    линейные блоки).
  • Если требуется валидность страницы, zoom должен быть
    спрятан внутри условных комментариев.

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

Для более детального обзора по метода вызова hasLayout и
сравнению hasLayout-хаков в разных версиях IE стоит ознакомиться со
статьей

«Мысли по поводу управлении хаками в IE»
.

Небольшое замечание по поводу IE Mac

IE Mac и IE для Windows — как два разных вида животных, обитающих в разных
вольерах зоопарка. У каждого имеется собственный движок визуализации, и IE Mac
совершенно ничего не знает о поведении hasLayout (или
contenteditable
). Движок IE Mac, по видимости, гораздо охотнее следует
стандартам, например, height рассматривается именно как
height
, а не как что-либо еще. Хаки и разработки для устранения проблем
hasLayout (особенно, при использовании свойств height
или width) вызовут нежелательные эффекты в IE Mac, и должны быть
скрыты от этого браузера. Более подробную информацию о проблемах, связанных с IE
Mac, можно найти в статье

IE Mac, странности и ошибки
.

MSDN-документация

В самой MSDN присутствует не так много информации об MS-свойстве
hasLayout
, и еще меньше информации о том, как обладание layout
влияет на модель визуализации в IE.

Если вернуться к IE4, то в нем почти каждый элемент имел какое-то подобие
layout
, исключая, быть может, простые линейные элементы, у которых нет
абсолютно позиционирования и размеров (MSDN — документ изменен1).
В этой ранней layout-модели были layout-свойства, такие как
border, margin, padding, которые нельзя
было применить к простому линейному элементу. Другими словами, выражение «иметь
layout» было лишь более изящной заменой для «могут иметь такие
свойства».

В MSDN по-прежнему упоминаются

layout-свойства, но их значение поменялось, они больше не связаны с
элементами, к которых есть layout. В IE5.5 было введено MS-свойство


hasLayout
в качестве более или менее внутреннего флага.

В IE5.5 документация Платформы Редактирования MSHTML (которая позволяет
редактировать «на лету», изменять размеры и перетаскивать элементы страницы,
применив <body contenteditable=true>) обозначает три важных аспекта
по поводу обладания layout:

  • Если у элемента страницы есть внутреннее содержание, то layout
    его содержания определяется ограничивающим его прямоугольником.
  • «Имеет layout», в основном, означает, что элемент является
    прямоугольником.
  • Фактически, «наличие layout» означает ответственность
    элемента за визуализацию его внутреннего содержимого.

(Платформа Редактирования — документ был удален из MSDN2)

Внутренние разработки, относящиеся к layout, были задокументированы
только в августе 2005, когда в результате взаимодействия

Проекта по Стандартизации Веба
и Microsoft лед тронулся, и Markus Mielke
[MSFT] сделал возможным более подробное обсуждение данной концепции:

В целом, элементы в Динамическом HTML Internet Explorer не отвечают за
собственное расположение. Элементы div или p могут
позиционироваться в соответствии с исходным кодом документа и общим потоком,
но их содержание будет расположено в зависимости от ближайшего предка, у
которого есть layout (зачастую это body). Элементы
используют layout этого предка, что проделать всю сложную работу по
определению собственного размера и других пространственных свойств.

(Обзор
hasLayout
)

Заглядываем внутрь

Наша интерпретация является не более, чем попыткой объяснить, почему дело
обстоит именно так в известных случаях, и ее следует использовать в качестве
руководства для случаев, которые еще не полностью изучены. Попытка разгадать,
что находится внутри черного ящика, путем исследования его поведения в некоторых
тестовых случаях обречена на неудачу. Также вопрос «Почему?» не имеет ответа. Мы
пытается понять внутренний механизм, благодаря которому работает вся модель
hasLayout, и как она влияет на отображение веб-документов. За
пределами понимания этого механизма возможно разработать только
руководства к действию
(и только руководства, а не универсальные
решения).

Мы думаем, что речь идет о небольшом выделенном «окне». Содержание элемента с
layout может быть полностью независимо от всего, что вовне. А также оно
не может влиять на внешние элементы.

MS-свойство hasLayout является в какой-то мере флагом: когда он
выставлен, у элемента есть его «layout-качество», которое поддерживает
некоторые специальные возможности: (например, обеспечивающие обработку
«плавающих» блоков и стека) как самого элемента, так и вложенных в него
элементов без layout-свойства.

Большая независимость layout-элементов
обуславливает то, что в большинстве случаев они ведут себя более стабильно, и
исчезают некоторые ошибки в отображении. Ценой такого поведения может быть как
значительное отклонение от стандартов, так и дальнейшие ошибки/проблемы в
отображении границ элементов.

Модель «MS-страницы», в терминах семиотики (научной дисциплины о знаках и
знаковых системах
), можно представить как набор маленьких несвязанных
блоков текста, тогда как HTML- и W3C-модель подразумевает «страницу» как
связанные последовательные текстовые блоки.

Обзор результатов

Неправильное обтекание и «несанкционированное расширение»

«Плавающие» блоки автоматически содержат layout-элементы. Это одна
из причин, из-за которых большинство новичков приходят в крайнее недоумение,
обнаружив в браузерах, поддерживающих стандарты, что на странице, сверстанной
под IE, «плавающие» блоки выпирают из родительского контейнера, если не убрано
дальнейшее обтекание.

Также возможно и противоположное поведение: если «плавающий» блок все же
должен выходить за пределы родительского элемента, например, в тех случаях,
когда автоматическое растягивание последнего не является желаемым эффектом. Для
получения представления об этом явлении можно ознакомиться со следующей
подробной заметкой:

В IE «плавающий» блок всегда «принадлежит» его родительскому контейнеру с
layout
. При этом последующие элементы учитывают только этот родительский
блок, а не вложенный в него «плавающий».

Тем самым, поведение IE6, когда он расширяет контейнер, чтобы в него
поместился другой, более широкий элемент («несанкционированное расширение»),
можно рассматривать как аспект правила «определения по ограничивающему
прямоугольнику».

Но ситуация еще хуже со свойством clear, которое не влияет на
«плавающие» блоки вне контейнера с layout, в котором находится элемент
с таким свойством. «Плавающая» разметка, которая использует эту ошибку в IE, не
может быть перенесена в другие браузеры без полного изменения самой верстки.

Свойство IE автоматически заполнять «плавающие» блоки, которого иногда нельзя
избежать, может быть смоделировано и в других браузерах, для дальнейшей
информации о позиционировании «плавающих» блоков ознакомьтесь, пожалуйста, с
разделом
Сходство с CSS-спецификацией
.

Элементы, следующие за «плавающими»

Когда блок следует за «плавающим» элементом, он должен, являясь блочным
элементом, игнорировать обтекание, но его содержимое должно быть вытеснено этим
«плавающим» блоком: текст в блочном элементе, следующим за элементом, для
которого задано float:left, будет располагаться справа от этого
«плавающего» блока и затем (если текста больше, чем высота у «плавающего» блока)
продолжится ниже его. Но если у блока с текстом есть layout, скажем, у
него задана ширина по некоторым причинам, весь элемент будет вытеснен
обтеканием, как если бы он сам был «плавающим», а текст в нем больше не будет
обтекать «плавающий» блок (он весь разместится справа в виде прямоугольника).

Ширина блока в процентах в IE5 вычисляется, исходя из доступного места сбоку
от «плавающего» элемента, а в IE6 на основе всей доступной ширины родительского
элемента. Поэтому в IE6 width: 100% выливается в некоторые
нестыковки по ширине «плавающего» блока со всеми остальными (и в массу других
проблем, которые из этих нестыковок могут следовать).

Тесты для случаев, когда hasLayout-блоки расположены рядом с
«плавающими»:

Похожим образом ведут себя и элементы с относительным позиционированием (position:relative),
которые следуют за «плавающими». По идее, они должны иметь смещение относительно
«угла отступа» (padding edge) родительского элемента (например, при
left: 0 такой элемент должен располагаться сверху «плавающего»
элемента (float:left), за которым следует). В IE6 смещение
left: значение;
начинается от правого внешнего угла «плавающего»
элемента, вызывая неверное расположение общей внешней ширины для «плавающего»
блока (решением может быть использование margin-left, но возможно
некоторые «неувязки» с процентными значениями).

По спецификации «плавающий» элемент перекрывает следующими за ним блоки. Это
не может быть достигнуто в терминах двумерных непересекающихся прямоугольников.

Если рассматривать неадекватное поведение IE дальше, то возникнет
справедливый вопрос, как заставить блоки в браузерах, совместимых со
стандартами, выглядеть так же, как и layout-блоки, «уступают» место для
предшествующего «плавающего» блока. Мы пытаемся ответить на него, используя
новый контекст визуализации блоков, следующих за «плавающим», в разделе
«Сходство с
CSS-спецификацией»
.

Если вы (повторно) зайдете на следующую страницу с ошибкой в IE6

то увидите, что layout-блок, который следует за «плавающим», не
отображает смещение в 3 пикселя, потому что эти 3 пикселя жестко привязаны к
«плавающему» блоку и не могут влиять на другие элементы за пределами layout,
но смещают весь элемент с layout на 3px. Layout можно сравнить
со щитом, который блокирует воздействие на содержимое, но которому передается
вся энергия от «плавающего» блока.

Списки

Списки реагируют на layout, переданный как самим списками (ol,
ul), так и пунктам списка (li).

Разные версии IE ведут себя по-разному. Наиболее характерными проявлениями
являются маркеры списка (списки с полностью измененным дизайном, где маркеры не
требуются, лишены этих проблем). Маркеры, по видимому, создаются некими
внутренними элементами, которые «присоединяются» к пунктам списка (обычно
прикрепляются снаружи) и являются очень не стабильными. К несчастью, так как они
являются внутренними, нет никакой возможности скорректировать их неправильное
поведение.

Наиболее распространенные эффекты:

  • Если списку присвоен layout, то маркеры исчезают либо начинают
    вести себя непредсказуемо или ошибочно.

Иногда это можно исправить, добавив полей к элементам списка. Это выглядит
как следствие того, что layout-элемент стремится обрезать содержание
вложенных элементов, выходящих за его пределы.

Следующей проблемой является то, что (в нумерованных списках) у любого
элемента с layout, по-видимому, присутствует свой собственный счетчик.
Возьмем, например, нумерованный список с пятью элементами, где только у третьего
есть layout. Мы получим примерно следующее:

1… 2… 1… 4… 5…

Далее, если элемент списка с layout состоит из нескольких строк, то
маркер будет выровнен по нижнему краю (а не по верхнему, как ожидается).

Некоторые из описанных проблем могут быть устранены следующим образом.
Например, если так необходимо иметь маркеры, то лучше избегать присвоения
layout
спискам и пунктам в них. Если требуется задать какие-либо размеры,
то их можно применить к другим элементам: например, ширину можно назначить
внешнему контейнеру, а высоту — каждому пункту списка.

Другая распространенная проблема со списками в IE возникает, когда содержание
любого li является якорем с display: block. В этом
случае пустое пространство между элементами списка не игнорируется и обычно
показывается как дополнительная строка для каждого li. Одним из
методом во избежание дополнительного пространства по вертикали является
присвоение layout этим блочным якорям. Дополнительным преимуществом
этого метода является создание всей прямоугольной области таких блоков
кликабельной.

Таблицы

У таблицы всегда есть layout, они всегда ведут себя как объекты с
заданной шириной. В IE6

table-layout: fixed
обычно равносильно таблице шириной в 100%
со всеми проблемами, которые это влечет (неверные вычисления процентных
значений). В качестве небольшого отклонения, можно рассмотреть

пару примеров
описанного поведения в IE5.5 и «режиме обратной совместимости»
в IE6.

Элементы с относительным позиционированием

Заметьте, что position: relative не вызывает hasLayout,
и это ведет к некоторым ошибкам отображения, в основном, к исчезновению или
неправильному размещению элементов. Несоответствия могут быть замечены при
обновлении страницы, изменении размеров окна, прокрутке и выборе или выделении
элементов. Выставляя это свойство, IE смещает элемент, но, по-видимому,
«забывает» послать сигнал «перерисовать себя» дочерним элементам из того же
layout
(элемент с layout отправляет такой сигнал совершенно
нормально).

описывают эти эффекты. Возьмите себе за правило никогда не позиционировать
элементы относительно без присвоения им layout. Также может
потребоваться проверить, нужен ли еще и родительскому элементу такой конструкции
layout и(ли) position: relative, это становится
действительно необходимым при работе с «плавающими» блоками.

Элементы с абсолютным позиционированием:

Принадлежат блоку — какому блоку?

Важно хорошо понимать CSS-концепцию блока-контейнера, который отвечает за
элемент с абсолютным позиционированием (АП), за его смещение и в зависимости от
чего считать его размеры в процентах.

Для АП элементов таким блоком является ближайший родительский элемент, у
которого выставлено позиционирование (position). Если таких
элементов найти не удается, то используется первичный контейнер для html.

Обычно такой контейнер выставляется путем при назначении элементу
position: relative
. АП элементы могут вычислять свои размеры и точки
отсчета независимо от основного потока документа. Например, их внедряют в код,
чтобы реализовать такой принцип, как «содержание — вперед» для повышения
доступности страницы или чтобы облегчить себе жизнь при верстке сложных
резиновых макетов.

Эта концепция подвергнута некоторой модификации в IE: смещение АП элементов
могут быть вычислены правильно только при наличии у их контейнера layout,
в противном случае ширина АП элементов, выраженная в процентах, может относиться
к неверному родительского элементу. В этом случае IE5 и IE6 ведут себя
по-разному, но в обоих браузерах наблюдаются проблемы. У IE7b2 более устойчивое
поведение, но все равно в некоторых случаях ошибочное. По возможности, пытайтесь
назначить layout родительскому блоку для АП элемента (т.е. чтобы не
было никаких других блоков между этими двумя).

Если мы хотим корректно работать со смещениями элемента, для родительского
не-layout блока которого выставлено относительное позиционирование, мы
должны присвоить этому родительскому блоку layout:

Если мы хотим выставить размеры (например, в дизайне страницы заложено ширина
в процентах) для элемента, для родительского блока которого не выставлено
позиционирование, то лучше отбросить саму такую мысль в силу отсутствия
нормальной поддержки таких трюков в браузерах:

Фильтры


Фильтры
, являясь исключительно MS-свойствами, применяются только к элементам
с layout. Это отражает их

собственный поток
обработки документа.

Изменение потока отображения

После визуализации всех элементов IE может изменить поток отображения для
блока, содержащего layout, при событии a:hover (например,
изменение background для ссылки). Иногда элементы перемещаются
из-за того, что в тот момент, когда произошло это событие, для всех элементов в
IE уже известны их размеры и смещения. При первой же загрузке страницы она
отображается постепенно, и часть данных не известна (в том числе, может быть не
известна ширина из-за эффекта «несанкционированного расширения»). Это может
привести к неожиданным перемещениям элемента при наведении (hover).

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

Происхождение фона

MS-свойство hasLayout влияет на расширяемость и позиционирование
фона (background). Например, по

CSS-спецификации
background-position: 0 0 должно
соответствовать «углу отступа» (padding edge) элемента. В IE/Win это
соответствует «углу границы» (border edge) при hasLayout = false
и «углу отступа» при hasLayout = true:

«Схлопывание» полей

MS-свойство hasLayout также влияет на «схлопывание» полей между
блоком и его блочными потомками.

По спецификации
верхнее поле блока при отсутствии у него верхнего отступа и
верхней границы должно «схлопнуться» с верхнем полем его первого блочного
потомка в стандартном потоке:

В IE/Win этого не происходит, если у блока есть layout: по-видимому,
он запрещает дочерним полям выходить за пределы родительского контейнера. Также
при выставлении hasLayout = true как для самого контейнера, так и
для дочернего элемента, начинают проявляться другие ошибки в вычислении полей:

hasLayout еще и влияет на кликабельную/наводимую область для
блочных ссылок. Обычно при выставлении hasLayout = false
чувствительна только ее часть, покрываемая текстом. Если же выставить
hasLayout = true
, то оказывается задействованной вся область. Описанное
верно для любых блочных элементов с прикрепленными onclick/onmouseover
обработчиками событий.

Погружение в навигацию по странице с помощью клавиатуры

Если при навигации по странице с помощью tab пройти по
внутренней ссылке, то при следующем нажатии клавиши tab фокус не
окажется на следующем якоре:

tab перенесет — и, скорее всего, неверно — пользователя к
первому якорю ближайшего родительского элемента с layout (если этот
layout
элемент образован table, div, span
или некоторыми другими тегами).

«Ужатие»

Некоторые свойства, примененные к элементам с width: auto,
заставляют их вычислять собственную ширину, используя алгоритмы «ужатия» (shrink-wrap).
Примерами таких свойств могут служить float: left|right,
position: absolute|fixed
, display:
table|table-cell|inline-block|inline-table
.

Это, в основном, работает в IE/Win, за исключением, конечно, неподдерживаемых
свойств. Но если у элемента, который должен «ужаться», присутствует дочерний
блок с layout, то в большинстве случаев дочерний элемент
раздвигается по всей доступной ширине, независимо от его содержания, препятствуя
тем самым «ужатие» родительского элемента.


Пример
:

«Плавающая» навигация слева, оформленная с помощью ul не может
«ужаться» из-за вложенных ссылок (a {display: block; zoom: 1;}),
которые оформлены таким образом, чтобы избежать дополнительного пустого
пространства в списке и расширить кликабельную область.

«Ужатие» остается в силе, только если у вложенного элемента с layout
выставлена ширина, либо у него присутствует какое-либо свойство, вызывающее
«ужатие» (например, float).

Обрезаем углы

В целом, если у блока довольно сложная внутренняя структура, в том числе,
элементы, выходящие за границы этого блока, выставление hasLayout
для такого контейнера часто бывает просто необходимо, чтобы избежать ошибок в
отображении. К несчастью, это почти обязательное правило вызывает проблемы с
другой стороны — со стороны границ блока: элемент с layout становится
полностью

независимым от всей остальной страницы
.

Если вложенные блоки выходят за границы такого контейнера (например, при
помощи отрицательных полей), то все «лишнее» содержание обрезается.

Восстановить такое содержание может быть восстановлено путем вызова
hasLayout
для внутренних блоков, также для IE6 требуется position:
relative
. IE7 ведет себя в этом отношении несколько лучше, для него
position: relative
уже не нужно.

Стек, слои и layout

По-видимому, существует 2 способа формирования стека и слоев в IE/Win:

Оба этих метода присутствуют в движке IE, хотя они и не совместимы друг с
другом. Возьмите себе за правило: при отладке не забывайте проверять оба
возможных поведения. Мы регулярно замечаем проблемы с выпадающими или другими
сложными меню, когда стек, позиционирование и обтекание вызывают многочисленные
неурядицы. В этом случае может помочь выставление z-index для
блоков с позиционированием, но этот эффект до конца не исследован, так что,
будьте осторожны.

Фиаско contenteditable

Атрибут contenteditable = true разрешает для HTML-тега (<body
contenteditable = true>
) редактирования «на лету», перетаскивания и
изменения размера как самого элемента, так и вложенных в него. Теперь попробуйте
это сделать с «плавающими» или layout-пунктами списка (li) в
нумерованном списке.

В процессе редактирования элементов contenteditable и
hasLayout
демонстрируют разный порядок в стеке для элементов с
hasLayout = true
(прим.: скорее всего, речь идет об эффектах,
подобных описанным для
нумерованных
списков
).

Парадигма Платформы Редактирования (документ удален из MSDN2)
является наследницей концепции layout, доказательством этому может
служить тот факт, что contenteditable приводит к неверному
представлению о layout (с учетом того, что в приложениях, каким-либо
образом интегрированные с движком редактирования IE, возникает необходимость
обратной совместимости и поддержки layout).

Сходство с CSS-спецификацией

Ваши страницы, сверстанные для MSIE, выглядят отвратительно в других
браузерах? Пожалуй, не стоит доводить до этого. Любой нормальный браузер с
легкостью может воссоздать MSIE-вид страниц, если его об этом хорошенько
попросить — и скормить немного корректного CSS-кода.

Используя легкое сходство между hasLayout и
основой

«нового контекста визуализации блоков»
, мы выявили некоторые закономерности,
которые позволили повторить эффект hasLayout для

«вытеснения «плавающих» блоков»
и его поведения с

«элементами, следующими за «плавающими»
в тех браузерах, которые
поддерживают стандарты.

Режим обратной совместимости

Пожалуйста, ознакомьтесь с нашими материалами по

режиму обратной совместимости в IE
для дальнейшей информации по поводу этого
режима визуализации страницы.

Layout. Заключение

Концепция layout, в целом, не соответствует некоторым базовым частям
CSS-модели визуализации документа, в частности, это касается потока, «плавающих»
блоков, позиционирования и слоев.

Причиной этому может быть частичное игнорирование IE/Win CSS-спецификации в
зависимости от того, есть ли элементов на странице layout или нет.

Наличие layout — часть другого движка?

По-видимому, объектная модель Explorer является каким-то гибридом модели
документа и стандартной модели приложения. Я акцентирую на этом внимание,
потому что это важно для понимания того, как Explorer отображает страницы.
Переход от модели документа к модели приложения является тем, что назначает
элементу layout.

(Dean
Edwards
)

В некоторых случаях невозможно дать корректную интерпретацию таким явлениям:
по-видимому, в зависимости от состояния hasLayout, используются 2
различных движка для визуализации страницы, каждый со своими собственными хаками
и ошибками.

Бессмыслица ошибок

Ошибки в программном обеспечении являются следствием человеческих ошибок и
недостатка профессионализма и логики в процессе создания приложения. Это
фундаментальный человеческий недостаток, и для него стоит найти долговременное
решение.

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

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

(Molly
‘the cat’
)

Эта статья была создана 30 июня 2005, последние изменения были в нее внесены
19 июня 2007.

Редакторы:

Особое спасибо за поддержку проекта:

Обсуждение статьи:

dean.edwards.name/weblog/

Обратная связь: spam.layout@satzansatz.de

Статья опубликована под лицензиейCreative
Commons
.

Оглавление

  1. Введение
  2. hasLayout:
    определение

  3. С чем
    приходится иметь дело

  4. Откуда появляется layout

  5. CSS-хаки
  6. Небольшое
    замечание по поводу IE Mac

  7. MSDN-документация

  8. Заглядываем внутрь
  9. Обзор
    результатов

  10. Стек,
    слои и layout

  11. Фиаско contenteditable

  12. Сходство с CSS-спецификацией
  13. Режим
    обратной совместимости

  14. Layout
    . Заключение

  15. Наличие layout — часть другого движка?

  16. Бессмыслица ошибок

  1. Оригинальный документ
    был изменен в MSDN. Мы основываемся на более
    ранней версии, которая доступна в Интернет Архиве (Управление
    Отображением, основанное на Свойствах Размера и Размещения
    )/li.

  2. Оригинальный документ
    был изменен в MSDN, но доступен в Интернет Архиве
    (Платформа
    Редактирования MSHTML в Internet Explorer 5.5
    ).

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

Источник:

http://www.satzansatz.de/cssd/onhavinglayout.html

Перевод:
http://sunnybear.habrahabr.ru/

Для вставки кода используйте HTML-теги
<pre><code class="php">ваш код</code></pre>

  • Познавательная новость. Было очень интересно прочитать сие. Выкладывайте побольше таких статей!