Пользователь
0,0
рейтинг
26 января 2009 в 02:10

Разработка → Баги IE. Часть 1. Наличие или отсутствие hasLayout

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

Первым постом хочу затронуть одно из фундаментальных понятий при исправлении багов IE — hasLayout.

Что такое hasLayout?


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

hasLayout это проприетарное свойство IE, которое определяет имеет ли элемент «layout» т.е. то, как элемент располагается в потоке, его размеры, позиционирование, реакцию на события и влияние на другие элементы.

HTML элементы, которые по умолчанию имеют «layout» (hasLayout = true): <html>, <body>, <table>, <tr>, <td>, <th>, <img>, <input>, <button>, <textarea>, <select>, <fieldset>, <legend>, <hr>, <iframe>, <embed>, <object>, <applet>, <marquee>.

Свойство hasLayout в IE нельзя напрямую установить, но на его наличие можно косвенно влиять различными значениями некоторых css свойств. Следующие значения перечисленных свойств дают элементу «layout» (hasLayout = true):
  • position: absolute
  • float: left или right
  • height, width: любое значение кроме auto
  • display: inline-block
  • zoom: любое значение кроме normal (невалидное свойство)
  • writing-mode: tb-rl
  • overflow, overflow-x, overflow-y: auto|scroll|hidden (только в IE7)
  • position: fixed (только в IE7)
  • min-width, min-height: любое значение (только в IE7)
  • max-width, max-height: любое значение кроме none (только в IE7)

Чтобы скинуть hasLayout нужно указать значение отличное от перечисленных выше (например: width: auto или float: none).

Более подробно о том, что такое hasLayout читайте в замечательной статье On having layout — the concept of hasLayout in IE/Win (перевод).

Как и зачем устанавливать hasLayout


Придание элементам hasLayout может исправить множество багов IE. Большинство багов, связанных с неправильным позиционированием, отображением или измерением связаны с наличием или отсутствием у элемента hasLayout.

Чтобы успешно исправлять эти баги прежде всего нужно узнать включен ли у элемента hasLayout. Это можно проверить аналитическим или опытным путем.

Первый подразумевает просмотр исходного кода стилей, применяемых к проблемному элементу, и сканирование их на наличие свойств-триггеров, перечисленных выше. Если у элемента, к примеру, явно задана высота (свойство height имеет значение отличное от auto) то свойство hasLayout установлено (его значение true). Если же свойств-триггеров не найдено, либо они имеют значения, которые сбрасывают hasLayout и элемент не относится к списку элементов имеющих «layout» по умолчанию, то свойство hasLayout не установлено.

Второй способ заключается в непосредственном просмотре значения свойства hasLayout элемента с помощью DOM инспектора в плагине Internet Explorer Developer Toolbar.
После того как вы установите плагин, на панели IE появится кнопка IEDevToolbarButton, при нажатии на которую откроется панель плагина:

IEDevToolbar
Также, открыть панель можно через меню View в IE6 (View → Explorer Bar → IE Developer Toolbar) или через меню Tools в IE7 (Tools → Toolbars → Explorer Bar → IE Developer Toolbar).

Для того чтобы выбрать элемент, у которого мы хотим проверить наличие свойства hasLayout, нужно нажать на кнопку inspect  и мышкой выделить его (аналогично тому как выделяются элементы в Firebug после нажатия на кнопку «Inspect»). После этого в панели «Current Style» будут показаны все стили, применяемые к выделенному элементу браузером. Если среди них нет свойства hasLayout значит элемент не имеет «layout». Если же среди них оно есть и его значение равно -1 (true), значит свойство hasLayout установлено, и элемент имеет «layout».

После того, как мы узнали как проверить включено ли свойство hasLayout самое время научиться правильно его устанавливать. Все перечисленные выше свойства-триггеры так или иначе будут влиять на отображение элемента. Если, к примеру, мы укажем элементу float: left; то, кроме необходимого нам эффекта (установки hasLayout), элемент будет вести себя в соответствии прямому назначению этого свойства (будет вырван из нормального потока и его будут обтекать другие элементы). Хорошо, если это совпадает с нашей задумкой, но чаще всего нам нужно просто включить элементу hasLayout.

Поэтому нам нужно такое свойство-триггер, которое, в идеале, никак прямо не влияет на поведение элемента. Таких свойств немного, в некоторых ситуациях таким свойством может быть height со значением 1% или display: inline-block, но все они имеют ограничения. Если использовать height: 1%, то в случае явно установленной высоты родительского блока, высота элемента, естественно, будет вычисляться относительно выставленного значения. На мой взгляд, наиболее безопасным можно считать свойство zoom с установленным значением 1 (масштаб 100%). Но, так как это свойство невалидно, лучше всего использовать его в отдельном файле стилей для IE, который подключать с помощью Conditional Comments. Все бы хорошо, но это свойство не поддерживается в IE < 6 так что, если вам необходима поддержка этих браузеров для них можно использовать display: inline-block или height: 1%.

Алгоритм поиска багов, которые можно исправить с помощью hasLayout таков:
  1. Найти несоответствие в отображении конкретного участка страницы в IE.
  2. Просмотреть кусок HTML кода этого участка с целью запоминания иерархии элементов.
  3. Найти стили в CSS, которые применяются к элементам на этом участке.
  4. Проанализировать все применяемые стили на наличие свойств-триггеров hasLayout как у проблемного элемента так и у его предков.
  5. Поочередно применять zoom: 1; к элементам, у которых не установлен hasLayout, начиная от самого верхнего в HTML дереве, при этом, после каждого изменения CSS файла проверять результат в IE.

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

Примеры: положительное влияние hasLayout


Предположим, что нам нужно расположить два блока внутри некоторого элемента. Один в левом верхнем углу, а другой в нижнем левом углу.
Код будет выглядеть примерно так:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="ru">
<head>
 <title>Пример 1. Неправильное позиционирование элементов с position:absolute.</title>
 <meta http-equiv="Content-Type" content="text/html;charset=utf-8"/>
 <style type="text/css">
  * {
   margin:0;
   padding:0;
  }
  
  .zoom {
   zoom:1;
  }
  
  div.parent {
   position:relative;
   border:1px solid #000;
   padding:20px;
   margin:10px;
  }
  
  div.parent div {
   position:absolute;
   width:20px;
   height:20px;
   top:0;
   left:0;
   background:#0c0;
  }
  
  div.parent div.bottom {
   top:auto;
   bottom:0;
  }
 </style>
</head>
<body>
 <div class="parent">
  <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
  <div></div>
  <div class="bottom"></div>
 </div>
</body>
</html>

* This source code was highlighted with Source Code Highlighter.

Пример 1

В нормальных браузерах все отображается как и задумывалось. Два зеленых квадратика, один из которых в левом верхнем углу элемента с рамкой, а другой в левом нижнем. Но, в IE6 все выглядит так:
Пример 1
Для того чтобы исправить это поведение нужно дать «layout» родительскому элементу (div.parent) для этого я добавлю ему специально заготовленный для этого класс «zoom». После этого все встанет на свои места:

Пример 1 (баг исправлен)

Рассмотрим следующий пример. Его код:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="ru">
<head>
 <title>Пример 2. Неправильная высота списка</title>
 <meta http-equiv="Content-Type" content="text/html;charset=utf-8"/>
 <style type="text/css">
  * {
   margin:0;
   padding:0;
  }
  
  .zoom {
   zoom:1;
  }
  
  div.parent {
   border:1px solid #000;
   padding:20px;
   margin:10px;
  }
  
  div.parent ul {
   background:#00c;
  }
  
  div.parent ul li {
   border:1px solid #000;
   background:#0cc;
  }
 </style>
</head>
<body>
 <div class="parent">
  <ul>
   <li>Пункт</li>
   <li>Пункт</li>
   <li>Пункт</li>
  </ul>
 </div>
</body>
</html>


* This source code was highlighted with Source Code Highlighter.

Пример 2

В нормальных браузерах, список внутри блока с рамкой заканчивается ровно там, где заканчивается последний элемент списка. В IE 6 и 7 нижняя граница списка совпадает с нижней границей блока с рамкой (это четко видно из-за того, что я указал списку синий бекграунд):
Пример 2
Опять же, после включения hasLayout у родительского элемента (div.parent) баг исчезает:

Пример 2 (баг исправлен)

Следующий пример. Есть некоторый общий контейнер в котором несколько зафлоаченных элементов:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="ru">
<head>
 <title>Пример 3. Выпадение зафлоаченных блоков из контейнера</title>
 <meta http-equiv="Content-Type" content="text/html;charset=utf-8"/>
 <style type="text/css">
  * {
   margin:0;
   padding:0;
  }
  
  .zoom {
   zoom:1;
  }
  
  div.parent {
   border:2px solid #000;
   margin:10px 20%;
  }
  
  div.parent div.float {
   background:#cc0;
   float:left;
   margin:2px;
   text-align:center;
   width:50px;
   height:50px;
   line-height:50px;
  }
 </style>
</head>
<body>
 <div class="parent">
  <div class="float">Float</div>
  <div class="float">Float</div>
  <div class="float">Float</div>
  <div class="float">Float</div>
  <div class="float">Float</div>
  <div class="float">Float</div>
  <div class="float">Float</div>
  <div class="float">Float</div>
  <div class="float">Float</div>
  <div class="float">Float</div>
  <div class="float">Float</div>
  <div class="float">Float</div>
  <div class="float">Float</div>
  <div class="float">Float</div>
  <div class="float">Float</div>
  <div class="float">Float</div>
  <div class="float">Float</div>
  <div class="float">Float</div>
  <div class="float">Float</div>
  <div class="float">Float</div>
  <div class="float">Float</div>
  <div class="float">Float</div>
  <div class="float">Float</div>
  <div class="float">Float</div>
  <div class="float">Float</div>
  <div class="float">Float</div>
  <div class="float">Float</div>
  <div class="float">Float</div>
  <div class="float">Float</div>
  <div class="float">Float</div>
  <div style="clear:both;"></div>
 </div>
</body>
</html>


* This source code was highlighted with Source Code Highlighter.

Пример 3

IE снова глючит:
Пример 3
После добавления класса zoom для родительского дива баг исчезает:

Пример 3 (баг исправлен)

Помимо исправления подобных багов, включение у элемента hasLayout полезно также для следующего:
  • Создание нового контекста форматирования (Пример 4).
  • В следствиии создания нового контекста форматирования запрет на обтекание плавающих элементов (Пример 5).
  • Фильтры применяются только к элементам с установленным hasLayout (Пример 6).
  • Исправление бага при котором display:inline-block применяется только к изначально строчным элементам. (Пример 7).

Негативное влияние hasLayout


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

Кроме этого, нужно учесть, что применение hasLayout плохо влияет на производительность.
Panya @Panya
карма
80,4
рейтинг 0,0
Реклама помогает поддерживать и развивать наши сервисы

Подробнее
Реклама

Самое читаемое Разработка

Комментарии (62)

  • НЛО прилетело и опубликовало эту надпись здесь
  • НЛО прилетело и опубликовало эту надпись здесь
  • 0
    а что если его установить вообще для всех элементов?
    • +1
      Ничего хорошего из этого не выйдет, кроме явных проблем с производительностью, это может привести к нежелательному поведению некоторых элементов, о котором я, кстати, написал в статье.
      • 0
        «После добавления класса zoom для родительского дива баг исчезает»

        о чём и спич
      • 0
        Производительность что так, что так плохая. Так что можно забить.

        Нежелательное поведение нужно досконально изучить. Все баги, которые вы указали в предпоследнем абзаце, также часто встречаются и с выключенным hasLayout, это говорит о том, что не hasLayout это рук дело. А конкретного места и времени.

        Я ставлю hasLayout сразу для всех div, ul, ol, li, и других блочных. И всё нормально.
        • 0
          Я точно могу сказать, что многие баги появляются именно из-за наличия hasLayout. Некоторые, конечно, появляются только в совокупности с другими свойствами, такие отловить довольно сложно.

          Я ставлю hasLayout сразу для всех div, ul, ol, li, и других блочных. И всё нормально.

          Это нормально? (обратите внимание на маркеры и их расположение). DIV ведет себя довольно предсказуемо.
    • НЛО прилетело и опубликовало эту надпись здесь
      • –1
        а почему бы и не? глючит и с ним и без него, только по разному. вопрос в том, какие глюки более серьёзные и какие чаще встречаются. а тормоза ты замерял?
        • НЛО прилетело и опубликовало эту надпись здесь
          • –5
            ну скажи ты честно, что не знаешь и боишься даже попробовать, но не надо высасывать аргументацию из пальца.
            • НЛО прилетело и опубликовало эту надпись здесь
              • –5
                навскидка тебя подвела. создай тестовый пример и убедись как ты был не прав.
                • НЛО прилетело и опубликовало эту надпись здесь
                  • –2
                    да, давай.
    • +3
      будет плохо.
      вот тут описаны результаты действия hasLayout — www.satzansatz.de/cssd/onhavinglayout.html#rev
      т.е. это не волшебная палочка что вдруг заставит всё в IE отображатся по стандартам, нет.
      это лекарство, которое полезно в малых дозах.
    • +1
      Зачем спрашивать — можно просто попробовать

      * { zoom:1 }

      …и пожалеть о сделанном. Рекомендую проверить.
      • 0
        и чего такого я должен вдруг увидеть?
        • +1
          Очевидно, нужно взять, не просто тестовый документ с парой параграфов, дивов и списков. Для теста предлагаю взять сверстанный, нормально отображающийся во всех браузерах, макет и первой строчкой написать это правило. Уверен на 99%, что в IE всплывет несколько багов, возможно даже, что все развалиться.
          • 0
            не менее очевидно, что если взять макет свёрстанный в квиркмоде, а потом перевести его в стандартмод, то он развалится. что это доказывает?
        • 0
          Как же я устал от твоего душного пустого новаторства.

          Хочешь что-то сделать удобнее, иначе, круче? Сделай!
          Расскажи, покажи… и мы стоя будем аплодировать.

          К чему эти пустые тёрки про «а вдруг hasLayout для всех блоков — это решение всех проблем». Или недостаточно мысли про то, что это тупиковая ветвь — если это свойство было исключено из движка IE8? Или сложно взять и попробовать, как пробовали все те, кто утверждает обратное?

          Не надо троллить. Очень прошу.
          • 0
            это почему это тебе можно троллить, а мне — нельзя? ;-)

            почему-то «все попробовавшие» так и не смогли родить хотябы одного конкретного примера ущербности пути лайаутизации всего — всё какие-то отмазки «глюки», «тупиковые ветки» да совершенно другой браузер «ie8 в режиме ie8»…
            • 0
              Посмотрите мой пример про списки. Это та самая ущербность. Мне несколько багов из моей практики так и не удалось воспроизвести, но я вас уверяю, что они тоже напрямую зависели от наличия hasLayout (я это проверял).
              • 0
                ок, 1 некритичный баг + (поверю тебе на слово) ещё несколько.
                а сколько багов возникает из-за отсутствия hasLayout?
            • 0
            • 0
              <ol>
              	<li>один</li>
              	<li>два</li>
              	<li>три</li>
              </ol>
              <ol style="zoom:1">
              	<li>один</li>
              	<li>два</li>
              	<li>три</li>
              </ol>


              • 0
                ну добавь исключение…

                * { zoom: 1 }
                ol { zoom: normal }
                li { display: list-item }
                • +1
                  Если есть желание доказать эффективность раздачи hasLayout всем блокам — прошу исследование на примере какой-нибудь вёрстки.

                  Ну, или можно троллить дальше. Счастливо.
                  • 0
                    вот я и прошу исследования, а не пустозвонства.

                    я тут нигде не утверждал, что раздача лайаутов — это хорошо; но с какой-то стати должен доказывать, что ваше мнение «Ничего хорошего из этого не выйдет» ошибочно.

                    что плохого в лайаутах кроме того, что никто пока не пробовал с ними подружиться?
                • НЛО прилетело и опубликовало эту надпись здесь
                  • 0
                    проще один раз убрать ненужное, чем каждый раз добавлять нужное.
  • +2
    • +3
      Это не очередной перевод этой статьи, дочитайте до конца. В моей статье упор делается на практической стороне вопроса. И 90% моей статьи это авторский контент.
      • +1
        тогда здорово, а я бы ещё дал подзаголовки с названиями багов, если таковые имеются — если человек уже знает баг, то может пропустить часть

        по поводу не скхалыпающихся маржинов — это влияние контекста форматирования
        • НЛО прилетело и опубликовало эту надпись здесь
  • +5
    Может быть дадим експлореру законно умереть. Я всё жду браузера с точным интерфейсом експлорера, но движком gecko или WebKit или оперу вывернутую до такого состояния. Что бы пересаживать всех кого только можно или писать сверху, что не плохо было бы обновить браузер до новой версии. Если это дело назвать iExplorer 10.0, то массы потянутся.
    • +1
      ждем релиза windows 7, и надеемся на то что она быстро разойдется в массы и у всех будет как минимум IE8 :)
      • +2
        в принципе если бы не было ie6, то уже можно было бы жить неплохо
    • 0
      Не надо ждать браузера с точным интерфейсом ). Он уже есть.
      Вот, читаем: habrahabr.ru/blogs/firefox/39134/
      и habrahabr.ru/blogs/firefox/9187/

      Так что вы можете уже сейчас сделать свою сборку :)
      • 0
        так может, и сборка уже есть?
      • 0
        Там ньюанс. Те кто любит осла приходят в шок от вида лисьего журнала посещений. А вариант встраивать IEtab в лису — это менять шило на мыло.
    • НЛО прилетело и опубликовало эту надпись здесь
    • 0
      И самое интересное, что через 9 месяцев после вашего комментария как раз и вышло то, о чём вы писали ;-)
  • НЛО прилетело и опубликовало эту надпись здесь
    • +1
      А как вы скачаете свой любимый браузер :)
      в обще это глупо давайте еще бороться против блокнота, проводника, и.т. И будем покупать только ядро и пялится на черный экран вспоминая команды на скачку программ. :)
      • +1
        Пусть links или wget встраивают (:
        А вообще замкнутый круг получается ):
      • 0
        Через ftp, очевидно :)
        • 0
          на ftp тоже както надо попасть
          • 0
            ftp.exe, очевидно =)
            • 0
              если вы помните где лежит каждый файл во вселенной то это не значит что все помнят, надо думать о большинстве а их устраивает и ie в стандартной поставке.
              • 0
                ftp ftp.opera.com
                • НЛО прилетело и опубликовало эту надпись здесь
                  • 0
                    А предполагается что юзер не умеет читать? Тогда, конечно, он ничего сделать не сможет. Но там же написано: This FTP server is anonymous only

                    ~> ftp ftp.opera.com
                    Connected to get1.opera.com.
                    220 (vsFTPd 2.0.3)
                    Name (ftp.opera.com:ivlis): anonymous
                    331 Please specify the password.
                    Password:
                    230 Login successful.
                    Remote system type is UNIX.
                    Using binary mode to transfer files.
                    ftp> dir
                    229 Entering Extended Passive Mode (|||15253|)
                    150 Here comes the directory listing.
                    drwxr-xr-x    4 0        0            4096 Feb 20  2007 pub
                    226 Directory send OK.
                    

                    Идём по дереву каталогов, и вот оно вожделение:

                    ftp> dir
                    229 Entering Extended Passive Mode (|||53782|)
                    150 Here comes the directory listing.
                    -rw-r--r--    1 0        0         5005112 Dec 15 15:17 Opera_963_classic_Setup.exe
                    -rw-r--r--    1 0        0         5619080 Dec 18 11:19 Opera_963_en_Setup.exe
                    226 Directory send OK.
                    ftp> get Opera_963_en_Setup.exe
                    local: Opera_963_en_Setup.exe remote: Opera_963_en_Setup.exe
                    229 Entering Extended Passive Mode (|||54108|)
                    150 Opening BINARY mode data connection for Opera_963_en_Setup.exe (5619080 bytes).
                    100% |*******************************************************************************************************|  5487 KB    1.18 MB/s    00:00 ETA
                    226 File send OK.
                    5619080 bytes received in 00:04 (1.17 MB/s)
                    


                    Ничего нет невозможно, если уметь читать и думать головой :)
                    • НЛО прилетело и опубликовало эту надпись здесь
                      • 0
                        Дело в том, что исторически в юниксах все удалённые клинеты подставляют в качестве дефолтного удалённого имени пользователя текущее имя в систем, что очень удобно, так как в 90% случаев так оно и есть. А в винде подставляется none, так как программа не может определить имя пользователся и надо насильно написать ононимус.
      • НЛО прилетело и опубликовало эту надпись здесь
  • 0
    Спасибо за статью, давно верстаю зная правила исправления багов, теперь пробелы восполнены.
  • +1
    Если я ничего не путал, writing-mode входит в CSS3.
    • 0
      Да, спасибо. Исправлено.
  • 0
    свойство zoom не поддерживается в IE < 6
    не поддерживается в IE < 5.5
    В IE 5.5 — поддерживается.
  • 0
    Спасибо. Продолжайте.
  • +1
    Очень скрупулёзно написано, здорово.

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