Тонкий CSS для Internet Explorer

IE6 самое популярное и устаревшее приложение на рынке под названием Internet. Это самый замечательный браузер 2000 года. Он не просто так приобрел свою популярность, его было за что любить, и можно постараться полюбить сейчас, когда он слишком медленно идет к 50% рынка.

Доклад рассказывает о решениях в верстке, которые приводят IE в соответствие виденьем w3c стандартов. Я покажу, как делать тонкий css толстым javascript'ом :)

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

Ошибки HTML

  • Картинки. При отсутствующем аттрибуте title всплывает подсказка, текст которой берется у alt (ie6, ie7);
  • Label. Тегу label необходим аттрибут for. Даже для такой удобной конструкции <label>Имя: <input/></label> (ie6);
  • PNG. Не поддерживает прозрачность (ie6).

Ошибки CSS

  • Наведение (:hover). Работает только для тега a у которого стоит аттрибут href (ie6);
  • Прозрачность. Своя реализация (ie6, ie7). Некорректно отображает прозрачные элементы без фона;
  • Наследование. inherit (ie6, ie7);
  • :first-child, :last-child. Приходится присваивать элементу класс (ie6, ie7).

Решения

Семантически верная верстка диктует свои условия. Удобным инструментом стала связка с Firefox + Firebug + Web Developer Toolbar. Internet Explorer все чаще стал запускаться под эмуляцией на Linux и Mac, это приводит к тому, что под него сайт тестируется в последнюю очередь. Даже windows-разработчикам приходится ставить две версии одновременно — 6 и 7.

А дизайнеры присылают все более сложные макеты страниц, основываясь на новых достижениях браузеров. У них же стоит Safari3 :)

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

Подключаем стили

Так как стили бывают очень сложными, я предпочитаю не смешивать правила для 6 и 7 версий в одном файле, а тем более объединять их с основными стилями документа. Для седьмой версии обычно пишутся 10-20% строк шестой версии. Общие стили для обеих версий подключаются через конструкцию @import. Иногда достаточно, чтобы файл шестой версии просто дополнительно подключал файл от седьмой.

HTML:

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

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

ie6.css и ie7.css
@import url(ie.css);

DHTML Behaviors

Behaviors разрабатывались для описания специфичной функциональности и поведения элемента. Внутри htc находится полноценный JScript, привязанный к каким-то событиям элемента и документа, например, наведение мышки или окончание загрузки страницы.
Подключается очень простой CSS–конструкцией:
behavior: url(behavior.htc);
Давайте посмотрим на программные решения.

Whatever:hover

http://www.xs4all.nl/%7Epeterned/csshover.html


По-моему, единственное популярное расширение, которое меняет именно поведение. Хорошо лечит свойства :hover и :active.
Чтобы его установить нужно прописать в любом месте стилей:
>body { behavior: url(hover.htc) }

Для работы нужна полностью загруженная страница, после чего он начинает парсить доступные стили. Найдя ключевое слово :hover и :active для стиля, он ищет в документе привязанные элементы. Если нашел, то создает события onmouseover и onmousedown, которые добавляют класс onhover.
К сожалению, у него есть минусы.
  • Тэг A без аттрибута href="" по-прежнему не работает;
  • При больших размерах документа или файла стилей, браузер может занять много ресурсов компьютера, потому что заново парсит документ;
  • Отрабатывает только в момент загрузки, для новых элементов, созданных например javascript'ом, требуется новое подключение, или такая запись * { behavior: url("hover.htc"); заметно нагружающая браузер;
  • С вложенными :hover ведет себя не всегда правильно.

IE PNG Fix

http://www.twinhelix.com/css/iepngfix/


Решает проблему с альфа каналом в png для 5.5 и 6 версий. Подключение:
img, div { behavior: url(iepngfix.htc) }
где div слой с фоном. Реализовано с помощью фильтра AlphaImageLoader. Что-бы решить проблему с некликабельными ссылками, ставит всем детям применяемого элемента style="position: relative". Отлично подходит для небольших изображений в маленьком количестве. На сложных макетах появляются врожденные минусы:
  • position: relative не помогает, если behavior накладывается на слой с position, отличным от static;
  • При медленной отдаче картинок сервером, или при их большом размере, пользователю некоторое время видны изображения без применения фильтра;
  • Показывает в статусной строке, сколько ему ещё осталось обработать изображений, примерно так: «Осталось 15»;
  • Для работы с картинками нужен прозрачный gif.

Expressions

Для того чтобы оценить плюсы и минусы «выражений» (expression), решения на основе behavior были описаны выше. Специальная конструкция expression по праву считается лекарством от всего. Благодаря ей полноценные JavaScript–выражения можно писать прямо в CSS–файле.

#id {
    свойство: expression(javascript код);
}
Свойство может быть существующим или выдуманным. Китайские верстальщики часто используют несуществующее свойство star.
Самое сложное в понимании экспрешнов — это нестандартный синтаксис. Новые команды разделяются не точкой с запятой или переносом строк, а запятыми. Самое логичное, что можно предположить — это функция. Т.е. мы передаем параметры в функцию, и она уже их выполняет.
Есть несколько особенностей у expression:
  • выполняется постоянно, если не переопределить CSS–свойство (см. «Оптимизация»);
  • выполняется мгновенно;
  • ключевое слово this необязательно, выражение this.style равносильно простому style;
  • работают комментарии /* */, несмотря на то, что мы находимся внутри css;
  • можно использовать внешние функции или библиотеки, если они объявлены или подключены в html;
  • пробелы могут вызывать ошибку, хотя такое встречается редко;

Оптимизация

Основа оптимизации — это переопределение CSS–свойств, которые содержат expression. Получить к ним доступ можно с помощью:
  • style
  • currentStyle
  • runtimeStyle
style — это style конкретного html элемента. Свойства из currentStyle мы можем только читать, зато currentStyle содержит все CSS–свойства, даже те, которые не понимает сам браузер. Свойства из runtimeStyle мы можем как читать, так и переопределять, но только те свойства, которые понимает браузер. Стоит заметить, эти свойства относятся к ноду, а не к CSS–правилу. Если мы изменяем runtimeStyle, то изменения касаются конкретного нода.

Приведу пример оптимизации. Допустим, у нас есть кнопки с прозрачностью.
    .button1 { opacity: .1 }
    .button2 { opacity: .2 }
    .button3 { opacity: .3 }
    .button4 { opacity: .4 }

Для ie, записи обычно дублируются:
    .button1 { filter: alpha(opacity=10) }
    .button2 { filter: alpha(opacity=20) }
    .button3 { filter: alpha(opacity=30) }
    .button4 { filter: alpha(opacity=40) }
Но мы можем применить экспрешн:
    .button1, .button2, .button3, .button4
    { filter: expression( 'alpha(opacity='+currentStyle.opacity*100+')' ) }

IE не завис? На четырех кнопках не должен. А вот на десяти и более, он иногда виснет и вылетает. Происходит это потому, что на каждое движение мышки по странице или выполнение JavaScript–кода происходит пересчет expression. Избежать пересчета удастся, просто переопределив фильтр в начале выражения:
    .button1, .button2, .button3, .button4
    { filter: expression( runtimeStyle.filter = 'alpha(opacity='+currentStyle.opacity*100+')' ) }

В презентации к докладу, есть более развернутый пример.

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

Такой способ оптимизации подходит только для «статичных» элементов, которым не нужно менять свое отображение динамически. Изменение родительского класса, равнение по высоте окна и эмуляция position: static — все это проблемные участки оптимизации. Лучше их не оптимизировать, а использовать пореже.

Дополнительные материалы

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

Презентация доклада.







Обсуждение