вторник, 4 марта 2008 г.

Nice Rounded Corners for IE, Safari, Firefox

Некоторое время я посвятил теме скругления углов у блочных элементов. Вот что получилось.

Цель
Разработать самый лучший (простой и надежный) метод для скругления углов у блочных элементов.
 
Требования
Необходимо достигнуть баланса со следующим списком требований:
  1. Никаких изображений. В крайнем случае — одно.
  2. Никакого яваскрипта. Должно работать без него. В крайнем случае — только expressions для IE. Т.е. случай с отключенным яваскриптом в IE принимаем за маргинальный.
  3. Работать должно во всех более-менее заметных браузерах и мобильных устройствах: IE 7, 6, 5.5; Firefox 2, 1.5; Safari 3, 2; Opera 9.5, 9, 8. В крайнем случае — только на наиболее популярных — IE 7,6; Firefox 2; Safari 3
  4. Визуальная привлекательность. Максимально быстрая отрисовка прямо со старта — именно поэтому никаких изображений и скриптов. Уж больно эти загружающиеся изображения и прочие тормоза раздражают.
  5. Валидность XHTML Strict 1.0 по нормам валидатора W3C и работа с content-type. "application/xhtml+xml" для всех кроме IE и c "text/html" для IE
  6. Расширяемость на будущее. Чтобы при появлениии новых версий браузеров это не сломалось.
  7. Валидность CSS 2 и отсутствие хаков в CSS. Это, пожалуй, недостижимо, но к этому нужно стремиться.
  8. Семантичность верстки. Никаких лишних сущностей в html-коде быть не должно. В крайнем случае — должен быть семантичный DOM.
  9. Оптимизация производительности. Главное — минимизация числа запросов к серверу. На следующем месте — минимизация трафика.
  10. Гибкая верстка. При изменении размера блока, масштаба страницы, размера шрифта, ничего разъезжаться не должно.
Анализ существующих методов
  1. Картинки в углы. Тормоза, лишние запросы. Несемантичный код или семантичный, но требуется включенный JS в IE.
  2. Буллеты в углы. Проблемы с масштабированием. Проблемы с читалками экрана.
  3. Эмуляция пикселов в углах через сетку html-тегов. Несемантичный код. Раздувание кода и стилей.
  4. Встроенные средства браузеров. Хорошо, но неуниверсально. CSS3 еще никто не поддерживает.
  5. SVG как фоновое изображение. Это безусловно будет хит. Но поддерживается пока только оперой 9.5 beta.
Процесс
В общем, как можно заметить, хороших способов нет. Точнее, их будет аж два: SVG как фоновое изображение и средства предлагаемые CSS3. Но это для культурных браузеров. А вот для IE ничего нет и не предвидится. И тут меня осенило: У IE начиная с версии 5.5 есть полный аналог SVG. Это VML!
Итак, после некоторых раздумий было решено: использовать VML для IE, а в остальных случаях использовать аналоги из CSS3.
 
Пример кода (демонстрация скругления углов через VML и CSS3). Для работы с VML нужно вначале включить namespace для VML. Потом нужно включить сам VML (в стилях). После чего можно использовать команды VML прямо в тексте:
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:v="urn:schemas-microsoft-com:vml">
<head>
<?import namespace="v" implementation="#default#VML" ?>
<style type="text/css">
  v\:roundrect {  display: block; }
  .block {  margin: 100px auto;  width: 50%;  position: relative;  padding: 10px; }
  .non-ie {  padding: 6px;  background: #FFF;  border: 4px solid #f0eeee; 
  -moz-border-radius: 1em;  -webkit-border-radius: 1em;  border-radius: 1em; }
</style></head><body>

<!--[if vml]><v:roundrect class="block" strokecolor="#f0eeee" strokeweight="4px" arcsize="0.1"><![endif]-->
<!--[if !vml]>--><div class="block non-ie"><!--<![endif]-->
<h1>Content</h1>
<p>Content of the block</p>
<!--[if !vml]>--></div><!--<![endif]-->
<!--[if vml]></v:roundrect><![endif]-->
 
Разные замечания:
  1. Можно ещё улучшить — подключить SVG, тогда заработает и в опере 9.5 и в других будущих продвинутых браузерах.
  2. Обратите внимание на условные комментарии для IE. Оказывается многие не знают как сделать "else".
  3. Комментарии можно вообще убрать. И использовать тег "v:roundrect" как блочный элемент (заодно и код будет семантичен). Я проверял — работает во всех браузерах. Можно даже content-type выставить в application/xhtml+xml. Но возмущается валидатор W3C. Можно дополнить DTD. Но это не понимает IE. Можно создать свой DTD. Но валидатор от W3C не понимает custom DTD. В общем, решайте сами, что вам валидней. Как по мне, так в данном конкретном случае валидатор от W3C конкретно не прав. Ну да ладно.
  4. Насчет оперы. Я очень люблю этот браузер. В том числе это означает и то, что я прощаю ему то, чего он не умеет. Он очень быстро развивается. Так что это не проблема.
  5. Я не в восторге от смешивания HTML и VML, но другого способа подсоединить VML нет.
  6. Те атрибуты VML-тегов, которые относятся только к VML нельзя переместить в стили. Увы.
  7. Если использовать VML-теги как блочные элементы, то они не понимают margin. Padding понимают. Есть и ещё мелкие странности. Типа отступов в 1px в некоторых случаях.
  8. Кривые в VML сглаживаются! Это выглядит просто отлично.
  9. Что делать с градиентами? VML и SVG их поддерживают. Можно и реализовать.
Итак, решение работает во всем чем только можно, исключая оперу. Лишних запросов нет вообще. Почти семантично. Отображается моментально. Красота.
 
Цель достигнута. Интересно только почему никто ранее не додумался до этого?

12 коммент.:

9 комментирует...

Ого! Мега круто. Впечатлен.

Павел комментирует...

В таких вещах самое классное - это процесс. Я около недели чистого времени угробил. Правда большая часть ушла на эксперименты с валидностью и с content-type "application/xhtml+xml". Нашел крайне интересные особенности работы браузеров. 8-) Например, оказывается, что пространства имен в стилях по разному обрабатываются для html и xhtml.

bolk комментирует...

Это у других браузеров есть аналог VML :) Всё-таки IE первые реализовали VML, потом только SVG появился :)

Павел комментирует...

Фигассе, Болк в блоге. Я знаменит! 8-)

Мне нравится VML. Правда несколько портят настроение разные мелкие и не очень глюки. Например, сейчас уперся в то, что в реализации VML под IE6 некорректно работает кеширование запросов на внешние объекты. Например v:image всегда спросит IfModifiedSince не смотря на Expire в будущем. В IE7 это уже залечили.
И ещё есть вагон мелких пакостей. Я как раз собираюсь более подробный пост на эту тему написать.

Gleb Arestov комментирует...

ссылка на файл не работает.

а что если vml вставлять через expression? каким нибудь там innerHtml

Павел комментирует...

Ого! Это я, похоже, случайно каталог удалил. Восстановил.

А вставлять через expressions по идее тоже можно, но они зависят от JS, поэтому я в этом направлении почти не экспериментировал. А сейчас и вовсе есть вероятность, что expressions в релизе IE8 будут работать только в режиме совместимости с IE7.

mihdan комментирует...

Эта техника детально описана с примерами и законченным скриптом на этом сайте

Павел комментирует...

Я в курсе, спасибо.
Всё равно приятно уметь обходиться без скриптов и разработать эту технику на год раньше. 8-)

Андрей комментирует...
Этот комментарий был удален автором.
Merlin SOI комментирует...

Снова пример не работает.
Восстановите, плиз, а то очень нужно под 6 IE такую задачу решить.
Спасибо!

Павел комментирует...

Не могу восстановить пример сейчас - я в отпуске ещё долго. Да и за истекшие годы накопились различные замечания к методу. Основная проблема - перестала работать резина начиная с IE8 в режиме соблюдения стандартов. Да и саму идею уже сто раз повторили разные авторы в js-примочках. Так что не жди, бери у них.

Merlin SOI комментирует...

На самом деле твой метод не работает только на IE8, что не критично.
Также хотел обойтись без JS, но раз без него никак - буду пробовать.
Спасибо.