Кросс-браузерный CSS без хака!
Задачи, которые у меня возникали в последнее время, натолкнули на идею простого написания кросс-браузерных CSS-файлов без использования хаков.
Возможно, эта идея не нова, и кто-то делал уже нечто подобное. Но я, по крайней мере, при беглом поиске ничего подобного не нашел.
Поэтому я хочу здесь поделится этой идеей, а заодно обсудить и, возможно, доработать ее.
Суть идеи я буду излагать на примере серверного языка PHP. Варианты для других серверных языков каждый сможет потом разработать самостоятельно.
Итак, перед тэгом <body> в нашем файле помещаем такой код:
<?php
$sBrowserClass = "";
if (preg_match("/Opera\W*(\d+(:?\.\d+)?)/",@$_SERVER["HTTP_USER_AGENT"], $aMatch)) {
$sBrowserClass = "isOpera";
if (@$aMatch[1] && $aMatch[1] < 9) {
$sBrowserClass .= " isOpera8";
}
} elseif (preg_match("/MSIE\W*(\d+(:?\.\d+)?)/",@$_SERVER["HTTP_USER_AGENT"], $aMatch)) {
$sBrowserClass = "isIE";
if (@$aMatch[1] && $aMatch[1] < 7) {
$sBrowserClass .= " isIE6";
}
}
if ($sBrowserClass) {
$sBrowserClass = ' class="' . $sBrowserClass . '"';
}
?>
<body<?=$sBrowserClass?>>
Теперь для IE7 тэг body будет выглядеть следующим образом: <body class="isIE">
Для IE6 и ниже тэг body будет выглядеть так: <body class="isIE isIE6">
Для Opera9 и выше тэг body будет выглядеть так: <body class="isOpera">
Для Opera ниже 9-й версии тэг body будет выглядеть так: <body class="isOpera isOpera8">
Для остальных браузеров тег будет выглядеть просто: <body>
Я исхожу из той мысли, что сильно старые версии браузеров либо вообще не берем в расчет, либо считаем их такими-же, как предпоследняя версия браузера.
Я думаю, что многие уже догадались, как должен теперь выглядеть css-файл в котором мы будем задавать стили.
Для тех, кто еще не догадался, я приведу пример:
#top_menu {
margin: 0px 5px;
overflow: hidden;
background: #DAE0D2 url("/images/m_bg.gif") repeat-x bottom;
padding-bottom: 1px;
display: block;
}
.isIE #top_menu {
height: 28px;
}
.isIE6 #top_menu {
height: 30px;
overflow: auto;
}
.isOpera #top_menu {
margin-bottom: 6px;
}
Теперь я думаю всем понятна структура этого CSS-файла.
Порядок работы у нас будет такой:
- сначала пишем полную версию CSS-файла и делаем его отладку, например на последней версии FF;
- пишем дополнения/изменения отдельных определений для последних версий Opera и IE;
- пишем дополнения/изменения для более старых версий Opera и IE;
Удобство данной методики заключается в том что вы располагаете все варианты написания CSS-определений под разные браузеры - в одном файле, в непосредственной близости друг от друга. Это позволит вам в последствии легко вносить изменения в этот файл - сразу для для всех браузеров. Вам нет необходимости использовать хаки, поэтому, с большой долей вероятности этот код будет правильно работать и в более поздних версиях браузеров. Незначительное увеличение CSS-файла никак не повлияет на общую скорость загрузки сайта, т.к. эти дополнения составляют, как правило, 5-10% от исходного размера CSS-файла. А иногда и того меньше.
Приведенный выше код сейчас, например, не учитывает что ваш сайт может по другому выглядеть в более старых версиях FF или в других браузерах. Но вы, при желании, можете сами его доработать. Здесь я привел его только для того чтобы было проще изложить суть моей идеи.
Если Вам не хочется использовать никакие серверные языки, и достаточно определить стили только для различных версий IE, то можно обойтись условными комментариями. Например, так:
<!--[if gte IE 7]><body class="isIE"><![endif]--> <!--[if lt IE 7]><body class="isIE isIE6"><![endif]--> <!--[if !IE]>--><body><!--<![endif]-->
Я считаю, что не надо бороться за то, чтобы проходил тест css-валидатора. Кроме вас, никто им пользоваться не будет. Пользователи дороже.
В конце-концов, хаки не от хорошей жизни появились.
По HTTP_USER_AGENT бессмысленно определять браузер.
Почему? Если кто-то настроил себе браузер так, что он некорректно посылает этот заголовок - это уже его проблема! Не надо умничать. ;)
Для большинства пользователей эта проверка будет выполняться правильно.
... conditional comments ...
Согласен, удобная штука. Именно поэтому я привел ее в конце. Но она не сработает в Opera.
плохо будут смотреться сохранённые локально страницы
Как правило, в каком браузере я сохранил. В таком и буду просматривать. Передавать другому я буду скорее ссылку, а не сам файл. Я думаю, что у нас уже прошла эра offline-браузеров. Ни для кого не проблема сейчас подключится к Internet и скачать этот файл заново (Ну за редким исключением, когда сайт, например, прекратил свое существование).
Но я бы не ставил эту проблему во главу угла!
Я считаю, что не надо бороться за то, чтобы проходил тест css-валидатора. Кроме вас, никто им пользоваться не будет. Пользователи дороже.
В конце-концов, хаки не от хорошей жизни появились.
А как-же стандарты? Для кого они пишутся? Разве не для блага пользователей?
Если выходит новая версия браузера - он будет с каждым разом все больше приближен к стандартам. Выходит, что пользователи использующие более новый браузер будут видеть этот сайт криво из-за хаков?
Нет! Я считаю борьбу с хаками правильной!
conditional comments.Тогда вероятность ошибки еще больше сократиться!
Александр Носов[досье] IMHO ваше решение и есть большой хак. Мало того, что оно ненадежно, так и непонятно, а что же оно позволяет решить?
Все проблемы с IE решаются с помощью средств, предоставленных Microsoft.
Про MZ разговоров меньше, хоть проблемы и есть.
Про Оперу - только ленивый не отметил ее изменчивость от версии к версии, и вряд ли кто-нибудь в состоянии описать все баги ее сборок даже внутри одной версии. Учитывая тот факт, что оперисты достаточно часто актуализируют версию своего браузера, вряд ли стоит беспокоиться о древних версиях.
А про Safari и остальные браузеры думали?
P.S. Ох уж это взывание к святым стандартам... В какой-то момент сервис валидации CSS на w3.org выдавал такую галиматью... Вроде бы уже исправили.
... решение и есть большой хак.
Можно и так сказать. Но оно выдержано целиком в рамках стандарта и позволяет сохранить валидность html и css. И при этом позволяет легко и просто сделать коррекцию таблицы стилей под любой браузер.
Я выступаю только против тех хаков при которых приходится писать "извращенный CSS", для которого нет никакой гарантии, что он будет правильно работать в новых версиях браузеров.
... и непонятно, а что же оно позволяет решить?
Главную мысль в этой методике можно выразить так:
- в тег body под различные браузеры добавляем дополнительные класс/классы;
- дополнительные стили для различных версий описываем относительно этих добавленных классов;
Т.о. мы можем скорректировать любой стиль, для любого тэга и для любого браузера.
С учетом всего вышесказанного привожу скорректированную версию php-кода:
<?php
$browserClasses => array (
"isOpera" => array(
"regExp" => "/Opera\W*(\d+(:?\.\d+)?)/",
"olderVer" => array("isOpera8" => 9),
),
"isIE" => array(
"regExp" => "/MSIE\W*(\d+(:?\.\d+)?)/",
"olderVer" => array("isIE6" => 9),
),
);
$sBrowserClass = "";
foreach ($browserClasses as $sBrowser => $aParam) {
if (preg_match($aParam["regExp"], @$_SERVER["HTTP_USER_AGENT"], $aMatch)) {
$sBrowserClass = $sBrowser;
if (@$aMatch[1]) {
foreach ($aParam["olderVer"] as $sAddClass => $nBeforeVer) {
if ($aMatch[1] < $nBeforeVer) {
$sBrowserClass .= " " . $sAddClass;
}
}
}
break;
}
}
if ($sBrowserClass) {
$sBrowserClass = ' class="' . $sBrowserClass . '"';
}
?>
<!--[if gte IE 7]><body class="isIE"><![endif]-->
<!--[if lt IE 7]><body class="isIE isIE6"><![endif]-->
<!--[if !IE]>--><body<?=$sBrowserClass?>><!--<![endif]-->
В первой части этого кода находится специальный конфигурациоонный массив, в котором Вы можете прописать параметры для любых браузеров, с учетом их предыдущих версий.
Поскольку здесь использованы условные комментарии - параметры MSIE из этого массива можно было-бы убрать, но я специально оставил их, для примера. Вы можете заменить их параметрами другого браузера - Safari, например.
Евгений Петров[досье] В чем конкретно вы видите ненадежность этого решения? Приведите пример, пожалуйста.
P.S. Извиняюсь, в приведенном коде опечатка.
Вместо:
"olderVer" => array("isIE6" => 9),
Следует писать:
"olderVer" => array("isIE6" => 7),
А как гугль и иже с ним отнесутся к тому, что в зависимости от USER_AGENT спайдер будет получать разный контент? Они же специально проверяют, что документ, который вы подсовываете индексатору, тот же самый, что и для браузера... или это относится только к тексту страницы, а классы не трогает?
В остальном - мне не нравится предлагаемое решение, поскольку оно завязано либо на IE-фичи (<!--[if ...]>), либо на динамическую обработку на сервере. Я часто использую SSI или вообще генерю статику, когда это позволяет концепция сайта, и у меня есть большое подозрение, что реализовать на SSI полноценную проверку браузера будет тяжело (а без SSI и подавно). Кроме того, я считаю что возможность смотреть сохраненные страницы любым браузером тоже имеет значение. У меня дома, например, под двумя разными аккаунтами стоят разные браузеры по умолчанию.
В общем: с хаками - один и тот же код смотрится одинаково во всех браузерах. С Вашими хаками - только в одном. Необходимость обработки на сервере (для общего случая, а не только для ИЕ), проблемы с кешированием, возможно, еще какие-то проблемы - и результат получается менее универсальным, чем при классическом подходе... Смысл?
Александр Носов[досье]
Во-первых, всегда ли можно точно определить браузеры, маскирующиеся под другие?
Во-вторых, давайте-ка приведу пример для того, чтобы Вы осознали все неудобство предлагаемого решения.
Компания осуществляет поддержку проектов, часть из которых создан с применением этого решения. В какой-то момент в этом проекте нужно произвести небольшие изменения, как-то: добавление графических элементов, косметические правки отдельных страниц. Что делает сотрудник отдела - он сохраняет код страницы, на которой нужно сделать правки. Делает это он, скажем, из FF. Вносит правки и открывает ее в IE, чтобы убедиться, что нет косяков и в нем. И что же - он видит непонятные баги, хотя открывая живой сайт в IE, проблем он не наблюдает.
Итог - все сотрудники отдела (верстальщики, контент-менеджеры) должны иметь список проектов, сделанных по этой технологии, чтобы при каждом изменении на этих проектах проклинать "того парня", который добавил им работы.
Сергей Пантелеев[досье]
Насчет Гугля, не уверен, но я думаю что он проигнорирует такую мелочь как добавление дополнительного класса в одном теге. Пусть меня поправят, если кто-то знает что-то по этому поводу.
Вы пробовали смотреть в IE даже полностью валидные странички, которые сохранены в FF? Мне ни разу не удавалось со своего диска нормально посмотреть в IE то что я сохранил в FF. Поэтому я стараюсь везде и всегда пользоваться одним и тем-же браузером.
Насчет SSI или жесткой статики - Вы правы. Но, ИМХО, здесь мне кажется достаточно будет условных комментариев. Как уже тут упоминалось выше уследить за "развитием" Оперы уследить очень сложно, поэтому для простых сайтов ее можно просто проигнорировать (в определенной степени). А для сложных сайтов нам без серверного языка не обойтись - тогда мое решение будет работать.
С Вашими хаками - только в одном браузере
Я как раз и пытаюсь объяснить что по моей методе можно задать стили для любого браузера, для страницы загружаемой с сервера. А при "классическом подходе" я не уверен что Вы всегда найдете хаки на все случаи жизни.
С кэшированием (например, на прокси) - могут быть проблемы. Согласен! Но я думаю что и тут можно что-то придумать. Сейчас я не готов ответить на этот вопрос. Возможно кто-то знает как решить эту проблему. Подскажите!
Евгений Петров[досье]
Да, некоторые браузеры маскируются под другие, но я думаю, что во-первых таких не много, а среди тех что есть не многие юзеры ставят себе такие настройки.
Я думаю что в обычном случае вы не станете специально писать хаки для этих "редких" браузеров. Поэтому и в моем случае их можно проигнорировать.
Но, если сейчас вы у себя поставите Opera выдавать себя за IE - в моем случае он все равно будет правильно опознан. Можете проверить! ;)
По поводу модификации кода. Ситуация которую Вы описали не такая уж и сложная. Даже если девелопер и не знал про "эту фичу" он достаточно быстро разберется в таком простом коде. Гораздо труднее ему будет подыскать нужные хаки при модификации. Кроме того насколько я знаю, при модификации, никто себе не сохраняет готовую страницу, а берут исходники с сервера.
Александр Носов[досье] Нет никаких "исходников с сервера" - все страницы генерятся. Сотрудникам придется вручную проставлять классы для проверки, либо генерить пяток одинаковых страниц. Это - ничем не обоснованная потеря времени сотрудников, а не "не такая уж и сложная ситуация". Вы не в состоянии разглядеть убыточность такого решения?
Ну что Вы прицепились к слову "хаки". Хак в моем понимании - нечто, не поддающееся пониманию и не имеющее логичного объяснения. Всем известно, что padding и border добавляются к width по стандартам, но это не работает в IE5 и в некоторых браузерах в quirks mode. Решение этого вопроса в виде внешнего блока с указанием размеров и вложенного блока для задания внутренних отступов - хак?
Что вообще в вашем понимании хак? Есть примеры?
Что значит "подыскать хаки"??? Мы говорим про ситуацию, когда так называемые "хаки" уже есть. Просто Вы предлагаете применять их по назначению класса body, я же предлагаю не ориентироваться на такой класс.
Евгений Петров[досье]
Стоп! Если все страницы генерятся - тогда тем более нет смысла сохранять готовую "сгенеренную" страницу для последующей модификации. Раз страницы генерятся, то значит на сервере они лежат в виде шаблонов, каждый из которых составляет какую-то часть сайта. Правильно?
Если-бы мне предложили модифицировать такой сайт, то первое что я сделал-бы — скачал полностью все его исходники себе на комп (или на какой-то свой сервер) и запустил-бы его у себя. А только потом приступил-бы к его модификации.
Делать модификацию на "живом" сайте ни один профессиональный девелопер не будет. Все исправляется на своем серваке. Тщательно тестируется. И только потом протестированные файлы выкладываются обратно на сервер. Согласны?
И вот тут, я пытаюсь вас убедить, что мое решение как раз помогает легко выполнить такие изменения. Т.к. вы видите CSS-файл целиком. С Вашего позволения, я повторю еще раз свой css-код:
#top_menu {
margin: 0px 5px;
overflow: hidden;
background: #DAE0D2 url("/images/m_bg.gif") repeat-x bottom;
padding-bottom: 1px;
display: block;
}
.isIE #top_menu {
height: 28px;
}
.isIE6 #top_menu {
height: 30px;
overflow: auto;
}
.isOpera #top_menu {
margin-bottom: 6px;
}
Смотрите как легко и понятно все читается:
- сначала идет общий код стиля заданного для тега с ID "top_menu";
- затем мы делаем коррекцию под все IE;
- потом небольшое изменение под IE6;
- потом под Оперу, и т.д.
Я нисколько не против внешних-вложенных блоков и это нисколько не противоречит тому что я предлагаю.
Я против решений такого рода:
Раньше мы для того чтобы IE6 не понимал какой-то стиль использовали, например, такую конструкцию div>#top_menu{...}. IE6 ее не понимал, а другие браузеры "проглатывали". Но вышел IE7 и все начало валится к "чертовой матери". Самое плохое, в этой ситуации что исправить такие хаки было ужасно трудно, так как применялись они безо всякой системы (так как хаков такого рода очень много и построены они по разным принципам).
В моем же случае все "разложено по полочкам" и даже если потребуется доработка CSS-файла под новый браузер - сделать это будет легко.
Александр Носов[досье] Ну как же Вам объяснить - стоит задача не менять сайт, а протестировать новый контент на одной или нескольких страницах (который меняется с помощью CMS, причем тут шаблоны). И никто не станет устраивать у себя копию 100 чужих проектов.
Что касается "проглатывания" A>B, то это совершенно нормальный селектор и отлично, что IE7 его понимает. Поэтому, те, кто использовал этот прием, должны были подумать заранее - а что случится, когда выйдет новый IE, который будет понимать и такой селектор, и min-width и т.д.
Между тем, conditional comments появились не вчера.
Евгений Петров[досье] Если новый контент создается в CMS по аналогии с уже имеющимся, с уже ранее использованными классами - то никакой необходимости в его тестировании на разных браузерах не будет. А если же создаются какие-то новые элементы - их по-любому тестировать прийдется, какая-бы метода не использовалась.
A>B я привел только как пример. Вы наверное знаете много хаков такого рода: http://centricle.com/ref/css/filters/
Вот, собственно, против таких хаков я и пытаюсь бороться!
А против conditional comments я ничего против не имею. Даже наоборот! ;)
ЗЛО!Потому что в них нет никакой системы, и их использование вызывает только путаницу - ничего более!
Александр, я отлично понимаю, что Вы боретесь за предложенное решение хотя бы потому, что оно придумано вами же.
Но, еще раз повторюсь, оно только осложняет работу. Поймите то, что я пытаюсь Вам сказать - при вашем решении для тестирования новых элементов в контенте придется либо запускать на локальном сервере проект, либо плодить несколько одинаковых страниц, либо каждый раз менять вручную класс в body. Первое потребует дополнительных затрат, как материальных, так и людских. Второе и третье - потеря времени.
Что же касается списка фильтров, который Вы называете злом, то для архаичных браузеров типа IE5 не считаю злом применить какой-нибудь "хак". Мало того, в сложных и функциональных проектах IE5+ просто вычеркивается как класс.
Евгений Петров[досье] Что я могу Вам сказать... Все зависит от того какую CMS вы используете!
Нормальная CMS должна позволять делать модульное построение страницы сайта, а не создавать каждую страницу целиком.
При модульном построении - у Вас будет единый (может пара-тройка) модулей создающих тэг <body>. Именно в этом модуле вы используете активный код который и будет проверять версию вашего браузера, а затем вносить коррекции в тег <body>.
Если ваша CMS построена не по модульному принципу, и при редактировании контента вы вынуждены править html-код всей страницы в целом. То тут я могу только развести руками — моя метода здесь не подойдет. Т.к. действительно прийдется создавать несколько версий одной и той-же страницы.
Но что-то мне кажется, что ТАКАЯ CMS будет очень не эффективна!
Если не секрет, на примере какой CMS Вы все это говорите? Это какая-то общеизвестная CMS?
Все CMS, что я знаю, допускают (и доже я бы сказал - "навязывают") использование модульного принципа построения страниц сайта.
Александр Носов[досье] Наверное, я очень плохо объясняю...
Я говорю не про программиста, а про контент-менеджера (либо верстальщика), которому, скажем, надо оформить страницу анонса какого-либо события со сложным хитросплетением графических и текстовых элементов. Что ему делать - сразу на живом проекте добавлять страницу? Конечно же нет - сначала надо ее сделать, а потом проверить соответствие ее внешнего вида макету.
Ну причем тут модульность, немодульность CMS - страницу сначала надо сверстать. А потом уже заносить и контент с помощью CMS и замещать css для этой страницы на сервере в случае каких-то дополнений.
А как ему проверять перед выкладкой, если для каждого браузера надо класс в body поставить? Или Вы предлагаете сделать актуальную копию проекта на внутреннем сервере и следить за синхронизацией с "живым"?
Евгений Петров[досье] Я думаю что в такой ситуации копия проекта на текущем сервере необходима.
Это не обязательно должен быть полный клон сайта. Это может быть только какая-то его часть, содержащая основные модули.
При верстке страницы по-любому будет удобнее редактировать только ту часть html-кода, которая составляет основной контент страницы, а не "ворочать" всю страницу целиком.
Если, как я уже говорил, речь идет о контенте, который создается на основе уже имеющегося - можно особо и не напрягаться по поводу разных браузеров. Достаточно будет посмотреть на него в одном-двух браузерах. При условии, конечно, что раннее подобная страница тщательно тестировалась во всех необходимых браузерах.
А если речь идет о создании нового, сложного контента, то правильнее его проверку поручить уже другому человеку, специально обученному для этого (тестеру). И это еще один "+" за то что бы все это происходило на локальном сервере, а не путем правки сохраненной страницы. При такой организации, когда тестер будет выдавать ошибки, а верстальщик будет ту-же их править - работа пойдет гораздо эффективнее. Согласны?
Ну а по поводу того что такой формат CSS-файла, как я предлагаю, будет максимально читабельным и удобным для правки — я так понимаю Вы уже не возражаете? ;)
Александр Носов[досье] Не могу больше пояснять свою мысль - устал... Если все так хорошо и устраивает - пользуйтесь.
Если вдруг будете организовывать отдел техподдержки клиентов (десятки и больше сайтов, разные хостинги, разные CMS, разные движки) - вспомните свои слова. Потому как мне кажется неразумным синхронизировать десятки разных проектов с имитацией условий их хостинга и движков у себя на сервере.
Это возможно только в исключительных случаях для "особенных" проектов.
Александр Носов[досье] Мне нравится предлагаемое вами решение. Да, у него могут возникнуть трудности с определением каких-то экзотических случаев user agent`ов, но общая прозрачность и, как следствие, лёгкость правки, имхо, это компенсирует.
А как ему проверять перед выкладкой, если для каждого браузера надо класс в body поставить
Вот уж не вижу здесь ничего сложного. Всё равно верстает, всё равно постоянно ковыряет файл, всё равно постоянно смотрит на этот файл в разных браузерах - поменять класс одного тега чтобы проверить эффект, ну... элементарно же.
GRAy[досье] Спасибо на первом добром слове, здесь! ;)
Хотя и против конструктивной критики критики я не возражаю! ;)
У меня например первая мысль была полностью отказаться от conditional comments, но после первого замечания со стороны Алексей В. Иванов[досье] я понял, что не стоит этого делать.
Еще бы мне хотелось услышать что-нибудь по поводу вопросов прозвучавших выше: о Гугле и о прокси. Если у кого есть какие мысли - подскажите!
fetis[досье] Как я уже сказал ранее - Вы можете создать стили для FireFox и для различных версий IE без использования серверного языка.
От Opera и других экзотических браузеров скорее всего прийдется отказаться.
Но специально для такого случая я хочу предложить такой вариант: проверять версию UserAgent при помощи JavaScript и добавлять соответствующий css-класс в тэг body. Учитывая тот факт, что наш добавленный css-класс выполняет лишь коррекцию стилей (основные стили будут загружены и применены без использования JS), то те немногие юзеры, которые работают с отключенными JavaScript скорее всего увидят страницу в более-менее удовлетворительном виде (но не идеальном).
Итак, по многочисленным просьбам, версия кода на JavaScript:
var browserClasses = {
isOpera : {
regExp : /Opera\W*(\d+(:?\.\d+)?)/i,
olderVer : {isOpera8 : 9}
},
isIE : {
regExp : /MSIE\W*(\d+(:?\.\d+)?)/i,
olderVer : {isIE6 : 7}
}
};
function addBodyClass() {
var sBrowserClass, sBrowser, sAddClass, aMatch, body;
sBrowserClass = "";
for (sBrowser in browserClasses) {
aMatch = browserClasses[sBrowser]["regExp"].exec(navigator.userAgent);
if (aMatch) {
sBrowserClass = sBrowser;
if (typeof(aMatch[1]) != "undefined") {
for (sAddClass in browserClasses[sBrowser]["olderVer"]) {
if (aMatch[1] < browserClasses[sBrowser]["olderVer"][sAddClass]) {
sBrowserClass += " " + sAddClass;
}
}
}
break;
}
}
if (sBrowserClass) {
body = document.body;
if (body.className != "") {
sBrowserClass = body.className + " " + sBrowserClass;
}
body.className = sBrowserClass;
}
}
window.onload = addBodyClass;
Код этого скрипта похож на тот код, что я приводил для серверной версии. В начале этого скрипта есть конфигурационный объект, в который вы можете добавить любые виды браузеров (как и в серверной версии).
Еще раз обращаю ваше внимание но то, что при использовании условных комментариев - из конфигурационного объекта можно убрать параметры MSIE. Я их оставил там для примера.
При правке конфигурациооного объекта будьте осторожны с запятыми. Не оставляйте запятую перед закрывающей фигурной скобкой! Многие браузеры этого не любят и Ваш скрипт после этого работать не будет.
Еще хочу обратить ваше внимание на то, что формат css-файла будет абсолютно одинаковым для обоих случаев (для серверного скрипта и JavaScript). Т.е. если вначале вы использовали версию на JavaScript а потом перешли на серверную версию - переделка css-файла не потребуется!
Для тех кто хочет оценить работу этого скрипта - предлагаю открыть в разных браузерах эту ссылку: http://www.alex.4n.com.ua/test.html (естественно при включенных JS).
В IE и FF при отключенных JS будет видна та "картинка", что требуется (благодаря conditional comments).
Александр Носов[досье] Мне тоже нравится ваш подход.
Собственно, спор разгорелся, как я понимаю, из-за частности - что в некоторых компаниях верстальщики имеют обыкновение править HTML-код готовой страницы, полученной по save as. Мне это обыкновение не кажется правильным. HTML, поступающий пользователю, может пройти множество стадий конверсии от оригинала к конечному варианту. Например, вполне нормально (и даже хорошо) его сжать, вычистив все пробелы, комментарии и пр. Экономия процентов 10, зато абсолютно бесплатная - в дополнение к gzip. А после такого сжатия страница нечитабельна и правке не подлежит. Страницы могут быть написаны вообще не на HTML, а на XML, с XSLT-конверсией на сервере. И т.д.
Насчет Google я бы беспокоиться не стал. Мелкие изменения для разных броузеров - это нормально. В Google не идиоты работают, чтобы банить, например, страницу, распечатывающую версию броузера.
А вот прокси - тут, боюсь, возможны заморочки. Популярные прокси обслуживают многие тысячи пользователей, и вовсе не факт, что они не выдадут клиенту неверную страницу. Вам придется запрещать кэширование на уровне прокси, а это чревато снижением скорости у посетителя, который пользуется таким прокси. Я сталкивался с ситуацией, когда, например, работа через прокси провайдера дешевле и несколько быстрее, пока ты ходишь на сайты, популярные среди клиента провайдера - ибо страницы с большой вероятностью скэшированы на прокси. Вы можете помешать такой оптимизации или, чего доброго, добиться неправильного показа страниц через не очень качественный прокси.
Отсюда вывод: мне больше нравится JavaScript-решение, корректирующее CSS. Разговоры насчет отключенного JavaScript мне не кажутся серьезными - если не считать "глубоко системных" панелей управления для сисадмина, которые должны работать из под Lynx на текстовом мониторе. CSS ведь тоже можно отключить.
Чисто серверное решение хорошо для сайтов, где можно смело запрещать всякое кэширование: у целовой аудитории почти наверняка неплохой интернет (скажем, это американцы или европейцы, или сайт обеспечевает продажу дорогих IT-продуктов и никак не ориентирован на "бедных домохозяек"), а страницы формируются динамически и почти всегда разные. Впрочем, это не такой уж редкий случай.
Даниэль Алиевский[досье]
- Не о верстке проектов я вел спор, а о добавлении сложного медиа-контента на уже существующие сайты.
- Мне кажется исключительно правильным работать с кодом, который непосредственно используется браузером для рендеринга страницы - любой пользователь видит именно то, что получает и отображает браузер. Ему глубоко фиолетово, что там происходит на сервере или по пути.
- IMHO для корректной и грамотной верстки проектов достаточно лишь conditional comments и знаний. Моя практика показывает, что те, кто ищет хаки для опер и т.п., генерят ужасный код.
- Очевидный минус решения - его ненадежность.
В общем, я остаюсь при своем мнении - это лишнее решение. Кому интересно, пусть используют.
Но, все-таки, хотелось бы выяснить - вот Вы, Даниил, будете его использовать?
Я года три назад пользовался решением, похожим на серверную версию предложенного. Но после пары десятков жалоб от пользователей и соответствующих правок регэкспов (каждый раз оказывалось, что какую-то вариацию UserAgent-а я в прошлый раз все-таки не учел, хотя так старался...) решил больше им не пользоваться:).
Применение JS для "затыкания дыр" верстки — имхо, зло, но минимальное и практически неизбежное (хотя бы пресловутые expression и behavior). На динамических сайтах, где без JS все равно никак (выпадающие менюшки, всевозможные AJAXовины и т.п.) — пожалуй, вообще не зло. Вот только ориентироваться при этом непременно на определение браузера и его мажорной версии, а не как таковой поддержки нужной DOM-фичи/CSS-свойства — на мой взгляд, по меньшей мере спорный подход...
С пп. 3 и 4 из последнего поста Евгения[досье] согласен полностью. Например, в приведенном примере проверка "на Оперу" непременно должна пройти раньше проверки "на IE", иначе многие Оперы получат IE-шные стили (кстати, разве перебор через for ... in гарантирует сохранение последовательности?)...
Евгений Петров[досье]
- Я не очень понял мысль. А что, разве если сайт уже существует, то это что-то меняет?
- Мне всегда казалось, что в любом программном проекте изменять лучше оригинал, а не конечный продукт. В чем отличие между правкой конечной HTML-страницы и исправлением двоичного кода EXE-файла или Java-класса? Оригинальные данные, существующие в виде системы различных скриптов, XML, фрагментов HTML, баз данных, по идее (при грамотной организации проекта) рассчитаны на то, чтобы их было удобно исправлять. Т.е. разбиты на соответствующие модули, подробно прокомментированы, окружены различными инструментами вроде системы контроля версий. Применяются разнообразные шаблоны, позволяющие многократно использовать код (скажем, все страницы формируются с использованием стандартных "шапок", меню, скриптов и пр.) Предусмотрены многочисленные способы сделать временное исправление, "откатиться" назад, завести отдельную ветку, пока не влияющую на основной продукт. Конечный же результат - неважно, в текстовом он представлен виде (HTML) или двоичном - рассчитан на то, чтобы им пользовались конечные пользователи. Которым совершенно наплевать на удобство потенциальной правки. В обычном программировании это так, разве в веб-разработке все иначе?
- Тут вам виднее, конечно. Я тоже не люблю хаки.
- Можно подробнее про ненадежность?
Но, все-таки, хотелось бы выяснить - вот Вы, Даниил, будете его использовать?
Я имею довольно отдаленное отношение к профессиональной разработке сайтов, я разрабатываю алгоритмы. Мой взгляд - "со стороны".
Еще одно соображение. В решении Александра вся "борьба с броузерами" сосредоточена в одном месте, в серверном скрипте (может быть, в клиентском js). Если обнаруживается новая проблема, или появляется новый броузер, достаточно исправить только один модуль. В классической же верстке с применением "лишь conditional comments и знаний", очевидно, методы обеспечения кросс-броузерности "размазаны" чуть ли не по всему коду множества страниц. Если, например, мой уровень знаний пока недостаточен, и я сверстал сайт, то при повышении моего уровня есть вероятность, что придется переверстывать все "с нуля".
Если, например, мой уровень знаний пока недостаточен
Про то и говорю, что каждым делом должен заниматься профессионал.
А что, разве если сайт уже существует, то это что-то меняет?
Конечно меняет - сайт разработан и реализован не нами. Контент заносится с помошью CMS. Кто будет ковыряться в шаблонах и модулях на чужом хостинге?
вся "борьба с броузерами" сосредоточена в одном месте, в серверном скрипте (может быть, в клиентском js)
Мне кажется, Вы не поняли суть решения. Она заключается в делении правил для различных браузеров. И вся разница между стандартным подходом и этим решенем в том, что в первом случае для разных версий IE вызываются свои файлы CSS (как правило, один единственный), а во втором все правила заключены в одном файле, только со своими классами body для разных браузеров.
О возможных проблемах с прокси уже сами написали. Что же касается JS-версии решения, у меня вопрос - а в какой момент будет прописываться класс в body?
Я имею довольно отдаленное отношение к профессиональной разработке сайтов, я разрабатываю алгоритмы
Аха. "Сам я не курю, а в камере пригодится".
В решении Александра вся "борьба с броузерами" сосредоточена в одном месте, в серверном скрипте (может быть, в клиентском js). Если обнаруживается новая проблема, или появляется новый броузер, достаточно исправить только один модуль. В классической же верстке с применением "лишь conditional comments и знаний", очевидно, методы обеспечения кросс-броузерности "размазаны" чуть ли не по всему коду множества страниц.
Даниил[досье], зато ведь и цена ошибки выше. В классическом "размазанном" решении все в основном рассчитано на отображение по стандарту и, если некий браузер неверно поймет данный конкретный хак — "косяк" вылезет исключительно в этом месте. В предложенном же Александром[досье] подходе, если по какой-либо причине браузер окажется неверно опознан, он получит, фактически, полностью чужую, заведомо неподдерживаемую (иначе не было бы необходимости в разделении) таблицу стилей...
Кроме того, постоянство мажорной версии далеко не всегда гарантирует однотипность поддержки CSS и отображения (особенно для Опер 7-8 это было актуально), иногда "характер глюка" меняется с установкой сервис-пака (вроде, бывало с IE5-6). Классическое решение (при наличии достаточных знаний и опыта, конечно) позволяет бороться с этим по мере возникновения — in-place. "Гадание" же по User-Agent'у, во-первых, не всегда позволяет выловить все влияющие факторы, во-вторых, учет все новых нюансов при очередном "исправлении одного модуля" приводит к лавинообразному усложнению проверок (по крайней мере, так выходило у меня, пока я не отказался от такого подхода). Плюс еще ранее упоминавшиеся трудности с поисковиками (в случае серверной версии)...
Ребята, если Вам "плевать на Оперу", то вы вполне можете использовать только conditional comments и не заморачиваться ни с какими серверными скриптами или JavaScript. Хотя, если честно, я не понимаю как вам может JavaScript помешать.
По-моему решение с JavaScript расставляет все точки над i. Без JavaScript у вас есть таблицы стилей для FF и всех IE-шек, а для Оперы и остальной "экзотики" будет использоваться JavaScript. И только маленький процент пользователей "экзотики", которые работают с отключенными JS или для которых не прописали специальных стилей - будут работать с теми стилями, что созданы для FF. Не думаю, что сайт при этом будет очень криво смотреться! Илья Cтpeльцын aka SelenIT[досье], ошибка в неправильном определении браузера практически исключена полностью, если правильно задать порядок определений браузеров и регулярные выражения для них.
Если использовать версию основанную на JS можно полностью забыть про проблемы с кэшем и поисковиками.
а в какой момент будет прописываться класс в body?
Евгений Петров[досье] вопрос с подвохом? ;) Т.к. я не не сомневаюсь, что Вы знаете как правильно это делать? IMHO это достачно это делать по onload. Поскольку у нас происходит только коррекция, а не определение стилей, то не думаю, что это сильно скажется на визуализации сайта. Но если для вас это будет принципиальным, то это можно сделать сразу после открывающего тэга <body>.
Ну и наконец, самое главное: каждый конечно вправе выбирать себе такую методику работы, которую он считает для себя максимально удобной. Но я считаю, что прописывать различные стили для одного элемента лучше в одном месте, чем размазывать это по нескольким файлам. И для правки это будет гораздо удобнее. Естественно, я не имею в виду, что у нас будет один огромный файл со всеми css-определениями. Мы разделяем css-ки по решаемым задачам, но не по типам браузеров.
P.S. Даже если я привык к какой-то методе и давно ее использую, но нахожу другую методу которая лучше в плане оптимизации выполняемой работы - я всегда беру ее себе на вооружение. Как правило - это оправдывает себя! Но это уже мое IMHO. ;)
Александр Носов[досье],
если Вам "плевать на Оперу", то вы вполне можете использовать только conditional comments
А можно, ради интереса, привести пару реальных примеров вопиющих расхождений между актуальными FF и Оперой, которые не обойти никак, кроме "грязных хаков" или ветвления по браузеру?
решение с JavaScript расставляет все точки над i
По-моему, для этого оно должно стать монстроподобным. Чтобы учесть нюансы минорных версий (стоит вспомнить отличие той же Оперы 7.5 от 7.2), "редких птиц" типа Safari и т.д... Имхо, чем учитывать все мыслимые нюансы и на каждый выставлять браузероспецифичную "подпорку", рациональнее изменить (упростить) саму верстку и привести ее к более-менее равнопонятному для всех состоянию... но это, разумеется, исключительно имхо.
Илья Cтpeльцын aka SelenIT[досье] Не могу, т.к. мои заказчики обычно требуют только FF, IE6, IE7. Поэтому я с другими браузерами заморачиваюсь "постольку-поскольку" ... Но я думаю Вы найдете массу примеров на этом форуме.
Чтобы учесть нюансы минорных версий ...
В обычной ситуации вы сильно будете учитывать нюансы минорных версий? Вот и здесь этого не стоит делать. Я не призываю делать стили для всех версий браузеров. Вы делаете стили только для тех версий, которые актуальны для вашего сайта. Если количество юзеров с определенным браузером составляет менее 1% - я не думаю, что под такой браузер стоит заморачиваться.
Александр Носов[досье]
А если просто вставлять нужный кусок кода в head с нужной ссылкой на отдельный css файл, под тип и версию браузера...
к пим.
echo '<link rel="stylesheet" type="opera/css" href="opera8.css">';
}
else
{
echo '<link rel="stylesheet" type="opera/css" href="opera9.css">';
}
....
так проще вроде
Но потом понял что не удобно, когда куски CSS-кода, относящиеся к одному селектору разбрасываются в разные файлы.
Сейчас мои коллеги, которые активно стали использовать предложенный мной способ, отмечают, что работать стало гораздо удобнее.
![[logo]](/site/images/logo.jpg)