Есть факт, что старый Internet Explorer неправильно складывает ширину плавающих слоев - так называемый 3px bug. Этот баг возник благодаря неуклюжей попытке создать запас на учет толщины границы охватывающего слоя - правила селекции областей. Старый Internet Explorer имел скрытый margin в 3 пиксела шириной, который в случае отсчета от границ body, отсчитывался вовнутрь окна.
Но правило - есть правило. Если селекция охватывает некоторую область, границы селекции должны находиться вне охватываемой области и занимать какое-то место вне этой области. Если область вокруг выбранного участка не может расширяться, это вызовет проблемы в любом броузере. Разработчики разных броузеров по-разному пытаются обойти этот конфликт. Но так как его невозможно разрешить строго математически, разработчикам броузеров приходится маскировать факт несоответствия, но это несоответствие все равно где-нибудь проявится.
В Opera, например, этот эффект обнаруживается на div-ах стопроцетной ширины, вложенных в ячейку таблицы, но проявляется он весьма неожиданно - при перерасчете контента, который был уже однажды помещен в слой, что бывает например при смене фона слоя по событию onmouseover. Причем, слой выпадает из ячейки, даже если этот слой ничего не содержит.
Я называю этот эффект - эффектом нотного стана. Рассмотрим пример таблицы из одной строки, как это бывает в горизонтальных меню.
В этом примере нет ничего, кроме смены className на новый стиль, содержащий другой цвет фона слоя. Кроме всего прочего, этот пример показывет, что свойство таблицы table-layout: fixed корректно работает только в Internet Explorer. В FireFox и Opera таблица все равно разьезжается. Интересно, что без свойства table-layout: fixed, таблица расширяется во всех броузерах, но по-разному. В Internet Explorer небольшой отступ появляется снизу, в FireFox - сверху. В Opera отступ изначально не виден, но появляется при смене className, создавая эффект нотного стана.
Попробуем выяснить, что конкретно не влазит в ячейку.
Вот ячейка таблицы, содержащая слой с высотой и ширинной по 100%.
(...content here...)
|
Никаких проблем нет. Однако, нам нужно расположить внутри этого слоя еще несколько пустых слоев.
|
В Internet Explorer все отлично работает вплоть до момента попытки заменить текст на заголовок. Вот так выглядит эта ячейка с дефолтовым заголовком:
(...content here...) |
Наконец понятно, что здесь что-то зарыто, но собака ли это? Известно, что умолчания для параграфа, списков и заголовков для разных броузеров различны. Попробуем свести различия к минимому, обнулив margin у заголовка.
(...content here...) |
В Internet Explorer и FireFox это сработало, но для Opera этого недостаточно. Если мы обнулим у заголовка также и padding это тоже не поможет. Опера по-прежнему сталкивает содержимое. Eсли создать специальный onmouseover класс для заголовка с нулевыми margin и padding в предположении, что Opera просто забывает атрибуты при изменении className, то это также ничего не даст.
Оставим только один слой с простым заголовком внутри. Эффект нотного стана останется, но поведение вложенного слоя неожиданно изменилось. Теперь ясно видно, что в Opera изменяется и высота слоя, и его положение.
(...content here...) |
Явное назначение положения не изменит ситуацию. Она изменится только при явном назначении высоты слоя.
(...content here...) |
Значит ли это, что Opera просто теряет размеры ограничивающей ячейки? Именно так. При перерисовке области внутри ячейки в Opera разрушается (теряется) иерархия отношений элементов таблицы. В нашем примере таблица была условно устроена следующим образом:
<table border="0" cellpadding="0" cellspacing="0"> <tr height="27px"><td> <div class="HeaderWraper"> <h5 class="Menu">(...content here...)</h5> </div> </td></tr> </table>
Очевидно при первом вычислении страницы опера понимает, что ячейка <td> имеет высоту, заданную в строке <tr>. При повторном вычислении <td> уже имеет неопределенное значение. Работать будет только явное назначение размеров для каждого <td> сделанное таким образом:
<table border="0" cellpadding="0" cellspacing="0"> <tr><td height="27px"> <div class="HeaderWraper"> <h5 class="Menu">(...content here...)</h5> </div> </td></tr> </table>
Теперь мы снова можем отказаться от явного назначения высоты вложенного в ячейку слоя:
(...content here...) |
Необходимо также избавиться от различий высот заголовков для FireFox и Internet Explorer. Например, для шрифта Verdana высотой 11px заголовки по умолчанию для Internet Explorer будут следующими:
Header 1 | font-size: 24pt bold size 6 | font-size: 32px bold |
Header 2 | font-size: 18pt bold size 5 | font-size: 24px bold |
Header 3 | font-size: 14pt bold size 4 | font-size: 18px bold |
Header 4 | font-size: 12pt bold size 3 | font-size: 16px bold |
Header 5 | font-size: 10pt bold size 2 | font-size: 13px bold |
Header 6 | font-size: 8pt bold size 1 | font-size: 10px bold |
Из этого примера видно, что никакие атрибуты шрифта заголовков, кроме высоты шрифта в пикселах, не обеспечивают кроссброузерной совместимости.
Таким образом, результирующий стиль, снимающий ограничения блочных элементов разных моделей броузеров будет следующим:
<style type="text/css"><!-- body { font-family: Verdana; font-size: 11px; border-style: none; border-width: 0px } p { font-family: Verdana; font-size: 11px } tr { font-family: Verdana; font-size: 11px } /* FireFox only */ div { box-sizing: border-box; -moz-box-sizing: border-box } p:first-child, h2:first-child, h3:first-child, h4:first-child, h5:first-child, h6:first-child { margin-top: 0px; margin-bottom: 0px } p:last-child, h1:last-child, h2:last-child, h3:last-child, h4:last-child, h5:last-child, h6:last-child { margin-top: 0px; margin-bottom: 0px } h1 {font-size: 32px; font-weight: bold } h2 {font-size: 24px; font-weight: bold } h3 {font-size: 18px; font-weight: bold } h4 {font-size: 16px; font-weight: bold } h5 {font-size: 13px; font-weight: bold } h6 {font-size: 10px; font-weight: bold } --> </style>
Если заголовки используются без стилей, переназначение стилей стандартных заголовков для FireFox будет таким:
html>body h1 { font-size: 32px; font-weight: bold; margin-top: 19px; margin-bottom: 19px } html>body h2 { font-size: 24px; font-weight: bold; margin-top: 19px; margin-bottom: 19px } html>body h3 { font-size: 18px; font-weight: bold; margin-top: 19px; margin-bottom: 19px } html>body h4 { font-size: 16px; font-weight: bold; margin-top: 19px; margin-bottom: 19px } html>body h5 { font-size: 13px; font-weight: bold; margin-top: 19px; margin-bottom: 19px } html>body h6 { font-size: 10px; font-weight: bold; margin-top: 19px; margin-bottom: 19px }
Для FireFox вместо комбинации стилей
h5:first-child { margin-top: 0px; margin-bottom: 0px } h5:last-child { margin-top: 0px; margin-bottom: 0px } h5 {font-size: 14px; font-weight: bold }
Можно написать просто:
h5 {font-size: 14px; font-weight: bold; margin-top: 0px; margin-bottom: 0px }
Вот окончательная таблица:
Хотя эта таблица выглядит во всех броузерах одинаково, но мы теряем возможность центрирования по вертикали с помощью margin. Обнулить только верхний margin недостаточно, так как в подобном случае заголовок выйдет снизу за пределы таблицы, хотя этого и не заметно явно в данном примере. Сместить текст в подобном заголовке можно рассчитанным значением верхнего отступа.
Но даже с рассчитываемыми значениями отступов не все так просто.
Заголовок с нулевыми полями:
(...Сontent here...) |
Высота этого заголовка не 14 пикселов, как можно было бы подумать, а 16, причем что-то добавлено сверху. Очевидно, реальная высота букв в заголовке высотой 14 пикселов составляет 16 пикселов вместе с диакритическими знаками. (В данном примере 14 пикселов - это высота скобки. Любопытно, что в многострочном заголовке высота строки составит уже 17 пикселов, а не 16. Для справки: в шрифте 11px высота строки составит 13px, а высота заглавных букв - 8px.)
Таким образом, верхний отступ в заголовке с нулевыми полями составит (27 - (14 + 2)) / 2 - 2 = 3 пиксела:
(...Сontent here...) |
Заголовок с высотой 100% и верхним отступом 3 пиксела уже не совместим с FireFox:
(...content here...) |