CSS-менеджмент: файлы
5 Февраль 2008Сегодня, когда большинство здравомыслящих разработчиков уже научились отделять содержимое от оформления, и большая часть работы по вёрстке сайта ведётся с файлами стилей, настало время поговорить об удобной организации этой работы. Ваши CSS-файлы превратились в бесконечные нечитаемые простынки, код пестрит множеством страшных хаков? Надеюсь, что нет, но всё же: перед вами некоторые советы по организации CSS, которые прозвучали на конференции РИТ-2007 в докладе «CSS-менеджмент».
Для удобства, выделим три основных уровня оптимизации:
- Файлы
- Блоки правил
- Правила
Сегодня речь пойдёт о файлах.
Разбиение на части
Для удобной организации работы с большими файлами стилей, рекомендуется разбивать их на несколько частей. Но тут же возникает вопрос: по какому принципу их разделять? Когда за дело берутся идеологи, либо сайт долго и вдумчиво проектируется, то иногда файлы организуются по принципу, который, из-за его красоты, я бы назвал «поэтическим»: большой файл стилей разбивается на малые по оформительскому признаку — в один файл всё, что касается общего макета, в другой всё, что касается размера и семейства шрифта, в третий то, что касается цветов, etc… Подобный подход можно было наблюдать на старом сайте компании Macromedia (RIP) или же на мастерски собранном сайте Digitall Web Magazine.
Принцип, как я уже говорил, красивый, но всё-таки, далёкий от жизни. Самый простой пример: для работы с одним блоком, вам нужно иметь отрытими минимум три файла. Не слишком удобно, учитывая то, что в каждом файле ещё нужно найти место, где этот блок описан. И так с каждым.
Более жизнеспособным, на мой взгляд, является функционально-структурный принцип, когда в отдельные файлы выносится описание свойств специфических функицональных элементов. К примеру: базовый файл стилей, описывающий весь макет, файл оформления форм, файл со стилями для каталога, галереи или всего многообразия кнопок, используемых на сайте. Увлекаться, конечно, не стоит: несколько файлов с двумя-тремя блоками правил скорее всего можно объединить, либо включить в базовый. Речь, главным образом, идёт о больших проектах, в которых объём CSS-кода выходит за рамки тысячи строк. Главное преимущество данного подхода состоит в том, что вы можете подгружать объёмные файлы стилей по мере их надобности: если ваш пользователь всего лишь зашёл на главную страницу и вряд ли пойдёт дальше, то зачем подсовывать ему стили каталога и восемь цветовых схем других разделов?
Вот пример разделения на файлы, которое использовалось при вёрстке портала LiveJournal.ru:
- reset.css — сброс умолчаний браузера
- layout.css — общий макет, универсальные блоки
- modules.css — всё многообразие модулей, блоков
- elements.css — типографика, сквозные элементы
Подключение к документу
Вполне логично мы подходим к вопросу о подключении стилей к документу. Здесь всё просто: существует всего два легальных способа и различные их комбинации. Наиболее эффективной комбинацией я бы назвал подключение корневого файла стилей при помощи элемента <link> и подключение дополнительных стилей уже в корневом файле при помощи директивы @import:
<head><link rel="stylesheet" type="text/css" href="style.css"/></head>
В самом начале файла style.css:
@import "layout.css";@import "forms.css";@import "catalog.css";
Вариант с элементом <style> и директивной @import прямо в голове вашего документа, как и HTML-комментарии внутри этого элемента, выглядят как архаизм: Netscape Communicator 4 — это уже история. Дополнительные стили для специфичных разделов подключаются либо при помощи @import при генерации корневого файла стилей на сервере, либо дополнительным элементом <link>.
В случае, когда количество запросов к серверу и, соответственно, время отдачи страницы, бывает критично, то можно пойти на автоматическую сборку CSS-файлов в один, для боевой версии, который дополнительно можно почистить от нефункциональных, с точки зрения браузера, символов. Но это эффективно только в случае создания именно боевых версий файла, работа над такой простынкой, особенно командная, превращается в мучение.
Управление хаками
Хаки — то самое сакральное знание, позволяющее взнуздывать непокорные браузеры. Ими тоже нужно эффективно управлять. Но прежде, стоит признаться, что сегодня большинство сайтов можно изготовить без применения хаков, если речь идёт о прогрессивных, так называемых, «правильных» браузерах: Firefox, Opera, Safari и парочка других, использующих те же библиотеки для обработки кода. Главной проблемой для вёрстальщика по-прежнему остаётся Internet Explorer. Само понятие хаков для вёрстки появилось, главным образом, благодаря этому браузеру и только для него и есть смысл их использовать.
Случаются, конечно, ситуации, когда какой-то специфический баг в «правильном» браузере сводит на нет ваше красивое решение и вроде бы можно прибегнуть к хаку, использующему какие-то ошибки, либо конструкции из CSS3, которые реализованы пока только в этом браузере (их ещё деликатно называют CSS-фильтрами). Но такие хаки, наряду с некоторыми хаками для IE, на мой взгляд, являются бомбой замедленного действия.
Показательна ситуация с популярной, некоторе время назад, конструкцией :root, которую понимал только Firefox. Поначалу, использование этого «хака» позволяло обеспечить чуть ли не пиксельную точность, но в один прекрасный день в свежей сборке Opera, а потом и в публичном релизе, появилась поддержка этого селектора. Что до ошибок в парсинге CSS, с помощью которых вы можете скармливать ваши свойства только нужным браузерам, то нужно признать, что новые версии «правильных» браузеров выходят довольно часто, чего только стоит бинарное обновление Firefox, которое скачивается в фоновом режиме и даёт о себе знать только в момент установки. Многие ошибки в свежих версиях правятся без предупреждений. И хорошо, если ваш опасный хак только наводит дополнительный лоск, а не является основой реализации всего макета.
Та же ситуация обстоит с обработкой ошибок в CSS и тех хаках, что основаны на этой особенности Internet Explorer, вроде _height, #width и //border. Вы уверены, что в будущих версиях IE подобный способ обработки ошибок сохранится? Вы уверены, что другие браузеры адекватно обработают эту ошибку в CSS-синтаксисе и не проигнорируют нижеследющие правила? Вы готовы рисковать? Я — нет.
Conditional Comments
И что же делать с хаками и другими конструкциями, необходимыми для нормальной работы IE? Самым удачным решением этой проблемы, на данный момент, является вынесение хаков для IE в отдельный файл и подключение его при помощи специальных HTML-комментариев, которые IE, в отличие от остальных браузеров, читает и исполняет, в зависимости от прописанных в них условий. Conditional Comments позволяют проверять версию IE, используя логические операторы больше, меньше, равно и их комбинации.
<!--[if IE 5]><link rel="stylesheet" type="text/css" href="ie5.css" /><![endif]-->
Вынеся все специфические конструкции в отдельный файл, вы избавитесь от необходимости писать перед каждым селектором или даже правилом всякую чушь, гарантирующую то, что это поймёт только IE.
Если использовать только данную технику, разнеся код для каждой версии IE в отдельные файлы, к примеру: ie6.css, ie5.5.css, ie5.0.css, то вы сможете с лёгкостью решить проблемы для каждой версии браузера, а также, при необходимости, в два движения избавиться от поддержки окончательно устаревшего браузера — всего лишь удалите конструкцию подключения ненужного файла и сам файл. Единственный минус данного подхода проявляется для высоконагрузочных проектов, когда важен каждый запрос к серверу. При использовании тактики раздачи файлов для IE по очереди, IE7 будет делать один запрос к серверу за дополнительным файлом, IE6 два, а IE5 целых три.
Решением этой проблемы может стать комбинация описанной техники с фильтрацией версий IE непосредственно внутри файла. Основа данного способа та же: мы подключаем при помощи Conditional Comments файл для всех версий браузера Internet Explorer, а уже внутри начинаем фильтровать браузеры по версиям в три этапа:
#box {width:500px;}* HTML #box {width:400px;w\idth:500px;}
Обычный селектор и обычные правила прочтут все версии IE, селекторы, начинающиеся с конструкции * HTML, поймут только IE6 и младше, а версии IE младше 6-й версии, к счастью, не умеют читать правила, в написании которых использовано вполне легальное экранирование: w\idth. Важно помнить, что можно экранировать все символы английского алфавита, кроме символов в диапазоне A—F. Поскольку хаки для IE5 зачастую пишутся только для того, чтобы компенсировать неправильную обработку блочной модели, и чаще всего приходится экранировать свойства width и height, то я взял за правило экранировать в них символ «i». Этот подход экономит долю секунды на раздумья «а какой символ мне бы экранирвать в этот раз?»
Как показали последние события, а именно обнародование механизма переключения будущей версии IE8 в Super Standards Compliance Mode (наряду с существующими Standards Compliance Mode и Quirks Mode) при помощи специфического мета-тега, наиболее безопасным вариантом подключения файла для текущей и более младших версий IE является условие if lte IE 7, т.е. «less then or equal» (меньше или равно). Потому как кто знает, что принесёт нам будyщая версия IE8, кроме прохождения теста ACID2? В случае с IE7, например, это был взрыв некоторых сайтов.
Продолжение следует…
Спасибо за за твои материалы. Очень грамотно и главное понятно. Ждем продолжения...
На данный момент актуальным является разработка сайтов для MS IE 6/7, Opera 9.x, FireFox 2.x.x.x - 3.x.x.x, Safari 3.x.x. Все эти браузеры, кроме MS IE 6, вполне адекватно следуют веб-стандартам и достаточно хорошо работают в режиме Standards Compliance Mode, таким образом остается проблема написания отдельно CSS-кода только для MS IE6 и решается она очень просто посредством использования Child Selectors, все выше перечисленные браузеры, короме MS IE6, понимают такие селекторы.
Приведу пример:
Всем известно, что MS IE6 не воспринимает свойство min-width, за-за чего возникает большая проблема при разработке "резинового" дизайна. Решить эту проблем, не используя JavaScript можно зафиксировав ширину сайта только для MS IE6
CSS:
body {
margin: 0;
}
#conteiner {
width: 1000px; /* Ширина для IE6 */
margin: 0 auto; /* Центрируем блок с контентом */
}
body > #conteiner { /* Используем Child Selector */
width: auto; /* перекрываем (overwrited) предыдушее значение параметра */
min-width: 800px; /* Устанавливаем минимальную ширину блока */
margin: 0; /* Отменяем центрирование */
}
(x)HTML:
<html>
...
<body>
<div id="conteiner">content</div>
</body>
</html>
> таким образом остается проблема написания отдельно CSS-кода только для MS IE6
Лихо вы дошли до такого вывода. Однако опыт показывает, что хаки приходится писать и для IE7, уж что за чудо получится из IE8 вообще никто не знает. А как быть со свойством opacity? Правильно — имитировать его при помощи IE-only фильтров. В итоге ваш основной CSS-код становится невалиден (читай — опасен). На данный момент sBMH и Conditional Comments — самое гибкое решение, безо всяких «но», которые возникают при использовании child-селектора. И я уж молчу про читаемость кода…
Хотел бы узнать ваше мнение по поводу использования expression. Например: P{padding-top:10px; padding-top:expression(110 + "px");}
Если вам хочется использовать гибкость CSS3 уже сегодня, то без expression'ов для IE не обойтись. Аналогичные JS-решения слишком громоздкие.
Но их ещё нужно уметь писать, чтобы при этом не ронять IE. Я знаю всего двух человек, которые это умеют. Почитайте: Тонкий CSS для Internet Explorer
Отличная статья! Очередной must read :)
>> Лихо вы дошли до такого вывода
IE6 сейчас худшее что есть у пользователей, а использовать хаки для IE5.x уже не актуально, если даже кто-то и пользуется подобным браузером, то это уже его проблемы и особого прироста в посещаемости такая несовременная неактивная аудитория не составит... Opera и FireFox постоянно бесплатно обновляются...
Я не спорю Conditional Comments несомненно очень удобный способ заставить ИЕ работать нормально
>> А как быть со свойством opacity?
записывать ИЕ фильтры через Conditional Comments :-)
Кстати просто opacity тоже не пройдет валидацию, это свойство появится только в CSS3, хоть валидатор для CSS3 на w3c уже доступен, но все же это еще пока не является стандартом...
>> использовать хаки для IE5.x уже не актуально,
Заказчики часто требуют в верстке поддержки IE5.x или Opera 7.
Переубедить сложно и приходится соответствовать.
2Octane: на работе иногда приходится сидеть через IE 5. Я пользователь. Пожалуйста, считайтесь со мной. :)
http://globalstats.hotlog.ru/
15% IE5
0% IE7
5% Mozilla
для меня были шоком. Или я не туда смотрю?
В Америках показатели (грубо)
30% IE6
30% IE7
40% Mozilla
Мне кажется, что лучше смотреть статистику Яндекса по браузерам
IE — 70.0
Opera — 16.5
Firefox — 9.52
IE 6.0 — 49.37
IE 7.0 — 19.79
IE 5.0 — 0.85
IE 5.5 — 0.22
Статистика Яндекса радует :-)
2keep: Вы же осознаете что ваш браузер морально устарел и не будете говорить на сайт "чо за фигня кривая" если там что то немного коряво, понимая что это скорее всего связано со старой версией браузера и сколько еще пользователей осталось которые пользуются IE5 не потомучто пришлось и осознают что это морально устаревший браузер, а потому что им так нравится. Тем более нормальный верстальщик не сделает так чтобы сайт вообще не работал в каком-то браузере, все хаки чаще всего применяются для сохранения дизайна...
На меня так все накинулись)) я не отрицаю использование хаков когда это необходимо, просто не люблю когда ими пичкают сайт чтобы во всех древних браузерах все смотрелось одинаково, хорошо если верстальщик выделит все хаки в отдельный файл и подключит его через Conditional Comments и пользователь современного браузера не будет грузить лишнюю нформацию, но когда ничинают писать всякие слеши и прочие символы прямо в основном CSS-файле сайта, мне кажется это слишком... В случае с Child-селектор на сколько я знаю (поправьте плз если ошибаюсь) все браузеры с поддержкой CSS2.1 распознают такой тип селектора, IE6 поддерживает только CSS2.0 и например чтобы решить броблему с min-width в случае блочной верстки достаточно просто заключить весь сайт в div и описать один раз для него ширину и минимальную ширину через Child-селектор ну или разбить на несколько блоков, кому как удобнее... или еще есть баг например с селектором :first-letter, в некоторых случаях IE6 вылетает с критической ошибкой если эта первая буква будет вложена в какой-либо другой тег, то решить можно например так: .article > p:first-letter { ... }
Подключение CSS через @import не всегда универсально, вот например однажды пришлось использовать вот такой хак:
Подключение CSS через @import не всегда хорошо, вот к примеру, мне недавно пришлось использовать вот такой хак:
<link rel="stylesheet" type="opera/css" title="" href="/css/opera.css" media="screen" />
Кстати говоря, хак понимает лишь Опера и Сафари, и это абсолютно валидно.
Кстати материал в тему digital-web.com/articles/CSS_not_hacks
> IE6 поддерживает только CSS2.0
Глупости. IE6 что-то поддерживает, а что-то нет. Так что высказывание «IE6 не поддерживает CSS 2.1» неверно.
> но когда ничинают писать всякие слеши … в основном CSS-файле
Я как раз и призываю вынести все хаки наружу. А если уж мы вынесли их наружу (туда, где их прочтёт только IE), то теряется смысл использования child-селектора.
У меня шаблон, который я использую для верстки по умолчанию подключает такие файлы:
reset.css
grid.css - layout
type.css - типографика, базовые стили для форм
elements.css - стили для всяких site-specific блоков (типа тизеров) и модулей
print.css - ага, для печати
Кроме того, по умолчанию через Conditional Comments подключаются
fix_ie.css
fix_ie5.css
fix_ie6.css
В эти три файла выносятся хаки для "ремонта" всех версий IE до 7 (первый файл), IE5 и IE6 (второй и третий, соответственно). Сюда выносятся только более-менее замороченные вещи.
Мелочевку (типа эмуляции min-width с помощью expression) не брезгую размещать в основном файле. Такой шняги обычно получается немного и она хорошо отработана, так что не страшно.
> Мелочевку типа … expression … в основном файле
А потом, наверняка не тестируете сайты в Safari? Видимо, придётся восстановить два поста про МойКруг, где я демонстрировал, как может невалидный CSS взорвать вёрстку сайта.
А можно узнать мнение профессионалов о сервисе Online CSS Optimiser ?)
Забавная и очень простая вещица. Вот, к примеру:
http://www.livejournal.ru/s/modules.css — 3255 строк кода.
Было 64.35 KB, стало 48.63 KB… экономия составила 24.42%.
И что мы получили на выходе? Абсолютно нечитаемые и невозможный для работы код. Зато сэкономили… Ни рыба, ни мясо. Имхо, этот вопрос решается, как я и говорил — красивой и удобной версией для разработки и той, что отдаётся клиенту после постпроцессинга.
А для этого есть уже более серьёзные вещи: CSSTidy
Мда ниодин из сервисов не справляетццо со значениями background, хотя конечно и я наверно чото намудрил, но без оптимизации во всех браузерах работает. Чтобы уменьшить количество запросов на сервер используются картнинки на которых размещено несколько изображений и комбинируя значения background-position отображается нужная область фонового рисунка в блоке фиксированных размеров...
например у нас есть:
.myClass {
background: #fff url(img/radio.gif) no-repeat top left;
}
.myClass:hover {
background-position: bottom left;
}
так CSSTidy найдет гденибудь background: #fff; и сгруппирует элементы с таким фоном именно в таком виде, сбрасывая все предыдущие значеия :-/ Хотя конечно чтоб такого не возникало надо сразу писать раздельно background-image, background-position, background-color и т.д. но это неудобна...
Во, можно воспользоваться функцией export в Opera Developer Console, она преобразует все параметры вида background: #fff url(img/radio.gif) no-repeat top left; в отдельные значения background-image, background-position, background-color и т.д., а потом уже запускать оптимизатор... но всеравно бред, преобразованный через Developer Console код слишком много весит...
Я точно знаю, что есть проекты, на которых используются как спрайты, так и CSSTidy. И как-то они там дружат. Уточню…
Спасибо! Интересная идея о логическом разделении CSS на части, буду использовать :)
по поводу CSS Optimizator'ов -- стоит весь код "резать" в последнюю очередь (а лучше, в предпоследнюю, при заливке на внешний тестовый сайт). Один из самых лучших оптимизаторов -- http://iceyboard.no-ip.org/projects/css_compressor/
Стоит, естественно, еще весь код в один файл объединять (через @media print|handheld|etc {}) и, по возможности, жать gzip'ом. Выигрыш просто сумасшедший получается: вместо трех файлов, загружающихся, к примеру, 400мс -- а страницу без них никто, кроме Opera, не покажет -- получаем 1 файл, который грузится за 50-100мс.
Подробнее:
http://webo.in/articles/habrahabr/14-minifing-css/
http://webo.in/articles/habrahabr/07-gzip-all/
А нужно ли использовать css оптимизатор, если потом файл все равно сжимается gzip'ом?
На больших файлах разницы по размеру почти нет, а возни больше. И всегда есть шанс что компрессор покорежит верстку.
ну если экономить каждый байт, то можно и пред сжатием его оптимизировать))) а вообще грамотный верстальщик уже на этапе разработки сгруппирует повторяющиеся свойства так, что эффект от подобных оптимизаторов будет минимален и уменьшение объема файла будет достигаться за счет удаления комментариев, лишних пробелов, знаков перехода на новую строку, последней в своде правил точки с запятой и прочего мусора... что в принципе можно сделать и самостоятельно, не опасаясь за потерю работоспособности кода...
Я тоже очень сомневаюсь в пользе оптимизаторов кода. Чистильщики — да, остальное — экономия на спичках, которых в хорошем коде практически нет.
По поводу хаков - мне понравился способ рализованный в extjs - там body присваивается класс (через JS) по имени движка браузера и, если нужно, его версии. Например, ext-ie7, ext-gecko и т.д. Очень удобно в том смысле что не надо использовать *, //, _ и т.п. хаки. Другое дело, если js отключен - тогда можно через noscript подключить css как описывается в статье.
Мне кажется, что более стабильным решением является серверная фильтрация, по заголовкам браузера. А ещё более стабильным — написание хаков только для IE, для чего у нас есть масса удобных средств.
Насчет серверной фильтрации мне нравиться больше. Учту. Спасибо!
Эхх блин, седня пришлось писать файлег со стилями для IE8b1, почемуто появляется куча прыгающего и появляющегося контента, хотя в ИЕ7 все идеально было, никакого эффекта от режима супер совместимости стандартам не заметил *TIRED*
p.s.: кстати в этом блоге в ИЕ8b1 проблема с заголовками, фоновое изображение видно целиком :-)