CSS верстка. Джедайские техники

Настоящие CSS- джедаи любят трудности. Правила хорошего тона заставляют их разносить в пух и прах очередную версию броузера Internet Explorer на форумах, но в реальности они любят IE. Ибо укрощение этого монстра тем и отличает мудрого джедая от падавана.

Когда по работе затишье, баги все поправлены, а новые ещё не обнаружены, возникает проблема чем бы занять себя. В такие минуты хорошо вспомнить о каком нить своём хобби, на которое вы согласны тратить кучу времени, не получая материального вознаграждения за это. У меня такое хобби - HTML/CSS верстка.

Как то раз я придумал себе изначально сложное задание, на которое не жалко было бы потраченного времени даже если ничего не получится. Само задание звучит просто: „Сделать верстку для своего блога используя внутри HTML только один DIV в который будет заключён основной текст страницы“. Что из этого получилось можно увидеть посмотрев на мой блог, а разные CSS хитрости узнать дочитав статью до конца.

Начал я с уточнения задания для самого себя. Выглядело это приблизительно так:

  • Внутри HTML должен быть максимум один тег DIV на любой странице сайта (далее под „сайт“ я подразумеваю свой блог).
  • Так как при подготовке статей к публикации на сайте я не использую WYSIWYG редакторы а пишу весь HTML руками- делаем макет используя спецификацию XHTML 1.1.
  • Работать должно во всех современных версиях броузеров. Для IE- начиная с версии 6.0.
  • Не используем JavaScript вообще, иначе слишком просто.
  • Футер прижимаем к низу, что бы уж совсем трудно было.
  • Визуальное оформление делаем максимально сложным. Закруглённые уголки, градиенты... Всё идёт в ход лишь бы жизнь мёдом не казалась :)

Далее необходимо было придумать HTML разметку. Мне очень хотелось что бы контент сайта был максимально ближе к началу страницы. Причины для этого две: есть гипотеза что поисковики такое больше любят + такие странички удобнее читать на устройствах с маленьким экраном. Остановился я на таком варианте:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>title</title>
</head>
<body>
<h1>
<strong><a href="/">header for site</a></strong>
</h1>
<div>
<p>content</p>
...
</div>
<hr />
<ul id="ww-menu">
<li><a href="#">top menu first item</a></li>
<li><a href="#">top menu second item</a></li>
...
<li><a href="#">top menu last item</a></li>
</ul>
<hr />
<dl id="ww-extra">
<dt><strong>Sidebar first- title</strong></dt>
<dd>Sidebar first- content</dd>
<dt><strong>Sidebar second- title</strong></dt>
<dd>Sidebar second- content</dd>
...
<dt><strong>Sidebar last- title</strong></dt>
<dd>Sidebar last- content</dd>
</dl>
<hr />
<address>
</address>
</body>
</html>

Смею наедятся что этот пример соответствует всем представлениям о семантике документа. Единственный спорный момент это использование <dl> для „сайдбаров“, но тут уж никак без этого. Специального тега в HTML не придумали, а единственный „разрешённый“ мне <div> уже был использован (помним о требовании один DIV на страницу). Второй момент- использование атрибута id для тегов: <dl>, и <address>. В принципе без этого можно было бы обойтись, если бы IE6.0 понимал CSS селекторы вида body>address{...}. Он это не понимает, но всё равно можно было бы применить такую хитрость; в файле CSS, который видит только IE6.0 (надеюсь вы знаете как это сделать при помощи Conditional comments) использовать следующий код:

body address{
тут пишем все те же правила,
которые написали для нормальных UA
в селекторе body>address
}
body * address{
а здесь сбрасываем в начальные
все правила, которые назначили выше
}

Таким нехитрым образом мы эмулируем работу сhild selectors в IE6.0

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

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

Проблема с height:100% в IE 6.0

Internet Explorer шестой версии, имеет один неприятный баг. Он неправильно считает 100% высоты для абсолютно позиционированных блоков. Test case демонстрирующий этот глюк. В зависимости от задач, которые вы хотите решить при помощи абсолютно позиционированного блока с высотой 100%, иногда может помочь такое решение проблемы. Задавать для блока максимально большую высоту в пикселях, и overflow:hidden для родительского блока.

Разделитель секций в документе

Именно так, как написано в заголовке, надо трактовать тег <hr> в наше семантическое время. Заблуждается тот кто думает что этот тег просто „рисует горизонтальную линию“. Это именно разделитель секций документа. По крайней мере такой смысл у него будет пока не начнут использовать HTML 5.0, в котором предусмотрен спец.тег для разметки секций (см. The section element).

Тег <hr> имеет три большие проблемы, которые резко ограничивают возможности по стилизации этого элемента средствами CSS. Все три проблемы связаны с IE (кто бы сомневался, sic).

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

Проблема номер два. В IE невозможно убрать уродливый дефолтовый бордер у тега <hr> и одновременно использовать фоновую картинку. В чем заключается великий смысл этого бордера, и чего он не убирается через CSS, это для меня великая загадка от MS. Но есть загадка ещё круче...

Проблема номер три. В IE высота <hr> ограничена ста пикселями. Что бы вы не писали в CSS- больше эта высота не станет. Можно попробовать использовать проприетарное CSS свойство „zoom:10;“ и тогда высота будет 1000 пикселей. Это единственный случай, который я знаю, когда свойство zoom используется не для хака по добавлению hasLayout property блочному элементу :)

Сами понимаете что жизни с вышеперечисленными проблемами в IE нет никакой, поэтому мной было принято некрасивое решение, подсовывать для IE дополнительный HTML код, который потом уже и оформлять средствами CSS. Выглядит это так:

<hr id="some-id" /><!--[if IE]><div id="some-id-ie"> </div><![endif]-->

В заключение этого раздела, привожу код, который делает тег <hr> одинаково выглядящим во всех броузерах (тонкая, серая линия, высотой 1 пиксель и с отступами по 7 пикселей сверху и снизу). Это часть кода из моего CSS-ластика:

hr{
margin:7px 0;
height:0;
color:#ddd;
background-color:#ddd;
border:1px solid #ddd;
border-bottom:none;
}
* html hr{
margin:0; /* for IE6 */
}
*+html hr{
margin:0; /* for IE7 */
}

Хитрый @import

Я думаю многие видели вот эту табличку - Hide CSS from browsers (@import). Мне необходимо было найти такое правило, которое позволяло бы разделить IE6.0 и IE7.0 при помощи CSS команды @import. Не надо спрашивать зачем мне это было надо. Допустим я сильно любопытный ;) Итак ищем инструкцию которую понимает одна версия броузера и не поймёт другая. Тупой перебор вариантов из вышеприведённой таблички, результата не дал. Долгие поиски в гугл ни к чему не привели. Пришлось запасаться временем и искать самому. Времени ушло много, но и результат есть (пробелы важны):

@import -: url("just-only-ie60.css");

Как вам такая „уличная магия“ ? ;)

Еще более хитрый @import

Есть такой древний trick, связанный с тем что IE не понимает указание media (в данном случае „screen“) в строке @import „modern.css“ screen;. Это приводит к тому файл „modern.css“ подключают все броузеры кроме IE. Многие не знают что на самом деле IE пытается загрузить файл "%22modern.css%22%20screen%3B". Т.е. имя файла начинается с кавычки и в конце точка с зяпятой. Есно обычно файла с таким именем нету в корне сайта, потому IE и „не понимает media“. Но можно научить IE хотя бы не делать левые запросы, засоряя логи сервера:

@import url(screen.css?) screen,\(\);

Нормальные броузеры все понимают как надо, а IE просит файл с именем "screen.css?%29%20screen%2C%5C%28%5C". Т.е. IE загрузит тот же файл что и остальные броузеры. Только вот остальные броузеры загрузят этот файл только в случае media=screen, а IE будет грузить его всегда. Ну и ладно, зато trick интересный ;)


Буду рад всем замечаниям по делу, относительно недостатков верстки которую я сделал. Особо интересуют замечания по поводу семантики, валидности HTML и CSS, и конечно описания глюков в отображении. Замечания по поводу внешнего вида (дизайна), тоже принимаются, но прошу не судить строго. Все таки я не дизайнер, как смог, так и нарисовал :)