-ms-filter, порождающий баги. Будьте бдительны

  • Tutorial
CSS -ms-filter bug

Привет, %username%.

В данной публикации будет рассмотрен безобидный, на первый взгляд, код который может вызвать недоумение — меню типа dropdown не будет работать в IE 7-8 из-за использования градиентного фона у контейнера.

В CSS есть хорошая функция — linear-gradient(). Благодаря ей мы имеем возможность создавать весьма сложные градиенты для применения в веб-разработке. Но вот браузер Internet Explorer, до девятой версии включительно, не выполняет данную функцию в связи с отсутствием ее поддержки на уровне обозревателя и, вместо нее, имеет собственную реализацию в виде CSS свойства и особого значения для него. Выглядит запись приблизительно так:

div {
      filter: progid:DXImageTransform.Microsoft.Gradient(params);
      -ms-filter: "progid: DXImageTransform.Microsoft.Gradient(params);
}
Свойство -ms-filter — запись согласно новой спецификации Microsoft.
Подробнее о градиентном фильтре для IE можно прочесть на htmlbook: http://htmlbook.ru/css/filter/gradient


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

Описание и воспроизведение ошибки


Фильтр для создания градиента, как и все реализации не поддерживаемых CSS правил в старых IE, обрабатывается при помощи JavaScript, а лишний JS сулит ошибками.

Не скажу что баг критический, но и не из разряда надуманных. Для воспроизведения нам понадобится классическое выпадающее меню реализованное на чистом HTML и CSS с использованием селектора дочерних элементов.

Я набросал простейшее меню для примера:

HTML
<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="utf-8" />
	<title>-ms-filter bug in IE 7-8</title>
	<meta name="description" content="A bug occurs in IE 7-8 when using the -ms-filter and CSS dropdown menu." />
	<meta name="keywords" content="ms filter, css filter, bug, microsoft, habrahabr demo" />
	<meta name="author" content="BR0kEN, Firstvector.org" />

	<link rel="stylesheet" href="menu.css" />
	<!--[if lt IE 10]><link rel="stylesheet" href="ie.css" /><![endif]-->
	<!--[if lt IE 8]><link rel="stylesheet" href="ie7.css" /><![endif]-->
</head>
<body role="document">
	<ul class="nav wrap clr">
		<li class="active"><a href="">Home</a></li>
		<li><a href="">Currency</a></li>
		<li><a href="">Macroeconomic analysis</a>
			<ul class="sub-menu">
				<li><a href="">Dean's FX</a></li>
				<li><a href="">Economic exposure</a></li>
				<li><a href="">Market pulse</a></li>
				<li><a href="">Central bank watch</a></li>
			</ul>
		</li>
		<li><a href="">Technical analysis</a>
			<ul class="sub-menu">
				<li><a href="">Forex</a>
					<ul class="sub-menu">
						<li><a href="">USD</a></li>
						<li><a href="">GBP</a></li>
						<li><a href="">EUR</a></li>
						<li><a href="">AUD</a></li>
					</ul>
				</li>
			</ul>
		</li>
		<li><a href="">Forex news</a></li>
		<li><a href="">Economic calendar</a></li>
		<li><a href="">Education</a></li>
	</ul>
</body>
</html>
menu.css
/* Base */
body {
	font-size:16px;
	font-family:Arial, Verdana;
	background:#f5f5f5;
}
a {
	text-decoration:none;
	-webkit-transition:all linear .3s;
	-moz-transition:all linear .3s;
	transition:all linear .3s;
}
ul {
	padding:0;
	width:1024px;
	margin:0 auto;
	list-style:none;
}
.clr:before, .clr:after {
	content:'';
	display:table;
}
.clr:after {
	clear:both;
}

/* Menu */
.nav {
	background:#4f4f4f;
	background:-moz-linear-gradient(top,#4f4f4f 0%,#494949 21%,#343434 67%,#292929 100%);
	background:-webkit-gradient(linear,left top,left bottom,color-stop(0%,#4f4f4f),color-stop(21%,#494949),color-stop(67%,#343434),color-stop(100%,#292929));
	background:-webkit-linear-gradient(top,#4f4f4f 0%,#494949 21%,#343434 67%,#292929 100%);
	background:-o-linear-gradient(top,#4f4f4f 0%,#494949 21%,#343434 67%,#292929 100%);
	background:-ms-linear-gradient(top,#4f4f4f 0%,#494949 21%,#343434 67%,#292929 100%);
	background:linear-gradient(to bottom,#4f4f4f 0%,#494949 21%,#343434 67%,#292929 100%);
	border-bottom:1px solid #cbcbca;
}
.nav > li {
	float:left;
}
.nav > li,
.nav > li > a {
	color:#fff;
	border-right:1px solid #dedede;
}
.nav li {
	position:relative;
	line-height:34px;
}
.nav > li:hover,
.nav > .active {
	background:#635f5f;
	background:-moz-linear-gradient(top,#635f5f 0%,#5a5656 30%,#484545 70%,#3f3c3c 100%);
	background:-webkit-gradient(linear,left top,left bottom, color-stop(0%,#635f5f),color-stop(30%,#5a5656),color-stop(70%,#484545),color-stop(100%,#3f3c3c));
	background:-webkit-linear-gradient(top,#635f5f 0%,#5a5656 30%,#484545 70%,#3f3c3c 100%);
	background:-o-linear-gradient(top,#635f5f 0%,#5a5656 30%,#484545 70%,#3f3c3c 100%);
	background:-ms-linear-gradient(top,#635f5f 0%,#5a5656 30%,#484545 70%,#3f3c3c 100%);
	background:linear-gradient(to bottom,#635f5f 0%,#5a5656 30%,#484545 70%,#3f3c3c 100%);
}
.nav a {
	display:block;
	color:#505050;
	padding:0 12px;
	font-size:16px;
	text-transform:capitalize;
}
.nav .sub-menu {
	display:none;
	position:absolute;
	z-index:9999;
	left:-2px;
	top:100%;
	width:230px;
	background:#fff;
	box-shadow:0 1px 5px rgba(0,0,0,.3);
}
.nav .sub-menu ul {
	top:40%;
	left:95%;
}
.nav li:hover > ul {
	display:block;
}
.nav .sub-menu li {
	border-bottom:1px dotted #ccc;
}
.nav .sub-menu li:hover > a {
	background:#e8e8e8;
}
ie.css
.nav {
	zoom:1;
	filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#4f4f4f',endColorstr='#292929',GradientType=0);
}
.nav > .active,
.nav > li:hover {
	filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#635f5f',endColorstr='#3f3c3c',GradientType=0);
}
ie7.css
.nav .sub-menu {
	border:1px dotted #ccc;
}
.nav .sub-menu a {
	height:34px;
}

Демо: http://firstvector.org/examples/ms-filter/index.html.

Выше описаны основные стили для меню и они предназначены для всех обозревателей окромя IE. Далее, внутри первого условного комментария, идут стили предназначенные для IE девятой и более старых версий, внутри второго — для седьмой (вообще для всех версий ниже седьмой, но они нас не интересуют).

Так вот, как мы помним, уже начиная с IE9 функция-ms-linear-gradient() работать не будет и ей на замену придет свойство -ms-filter из файла ie.css.

Хронология событий

IE9 — все работает как надо.
Скриншот

IE8 — видим, что выпадающего меню нет.
Скриншот

Хотя, если присмотреться в выделенную область, можно заметить что меню отобразилось, правда поведение его таково, будто у одного из его родителей установлено overflow: hidden;. Но мы знаем что его нет и знаем в почему так получилось. Оставляем в файле ie.css следующее содержимое:

.nav {
	zoom:1;
}

и проверяем — все работает, но градиентами пришлось пожертвовать.
Скриншот

Возвращаем ie.css к изначальному виду и проверяем работоспособность в IE7 — не работает.
Скриншот

Ожидаемо, т.к. в восьмой версии, было также. Но, что интересно, дабы исправить ошибку в этой версии, потребуется удалить лишь градиент отображаемый при наведении на пункт. Приведем ie.css к виду:

.nav {
	zoom:1;
	filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#4f4f4f',endColorstr='#292929',GradientType=0);
}
.nav > .active {
	filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#635f5f',endColorstr='#3f3c3c',GradientType=0);
}

и проверим — вновь работает, но при hover-эффекте используется монотонный цвет.
Скриншот

Примечание: для воспроизведения данной ошибки нет разницы в том, как будет написано имя свойства: -ms-filter или просто filter, баг даст о себе знать в любом случае.

Итоги


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

p.s. Я не сомневаюсь в том, что помимо описанных ситуаций можно воспроизвести подобные на этой же почве, или наоборот — отыскать иные методы преодоления.

Спасибо за внимание.

Similar posts

AdBlock has stolen the banner, but banners are not teeth — they will be back

More
Ads

Comments 23

    +8
    Как же хорошо, что меня не беспокоят IE < 9, чего и вам желаю)
      +2
      Спасибо, но, увы, мои беспокойства начинаются от IE7.
        +1
        я думаю в данном случае градиентом для IE < 9 можно со спокойной душой пожертвовать.

        а баг интересный, конечно (как и львиная доля багов IE): такие баги заставляют изрядно поковыряться и понервничать
          0
          Солидарен. По хорошему, неплохо бы иметь два внешних вида: один для IE <= 8, попроще, а второй — для остальных браузеров. Затем проверять юзер-агент и отдавать необходимый шаблон.
            +1
            ну зачем шаблон другой. очень многие подобные баги исправляются посредством CSS (и бубна). неподдерживаемые фичи можно просто не реализовывать (например как в вашем примере — не хочет нормально работать с градиентами, пусть будет сплошной цвет), для всяких фиксов/полифилов подключаеются отдельные файлы через conditional comments
              +2
              С моей точки зрения, люди, использующие устаревшие браузеры, не нуждаются в дизайнерских прелестях веб-сайта. HTML5 теги в IE <= 8 создаются при помощи JS, в IE7, таким же способом, — псевдоэлементы. И эти действия потенциально опасны. И на текущем проекте я достаточно сильно это почувствовал.

              Оптимизировать разными уловками можно, так и поступается каждый раз.

              В данной ситуации хороша аналогия с людьми в возрасте: обучить мою бабушку пользоваться планшетом — очень трудно, а радио — пол часа. По-этому для «старичков», нужно отдавать изначально оптимизированный для них шаблон, а «молодежи» — с использованием передовых разработок.
        0
        а на сколько вас не беспокоят IE < 9?
        не беспокоят вообще
        или доводите в них проект до минимальной работы основного функционала?

        если первый вариант — я вам уже завидую
          +2
          Вообще.
          На одном проекте, правда, пришлось подправить пару вещей в JS для совместимости с IE8, но это одно исключение (сам сайт выглядит далеко не так, как в остальных браузерах в плане рюшечек, и никто об этом не парится, хоть как-то с первого взгляда работает — и хватит).
          В целом, все с кем сотрудничаю понимают, что старые версии браузеров не актуальны, и вкладывать ресурсы в их поддержку не рационально.
          Нормальная практика — (последняя версия — 1)+.
          Иначе получается, что мы как разработчики хотим стремиться вперёд но при этом ставим костыли смотря назад, не хорошо получается.

          P.S. Если честно, то даже IE9 меня беспокоит крайне мало (иногда можно зайти посмотреть, если есть что-то под рукой с Win7, хотя обычно его нет). Нормально — когда я просто пишу код по стандартам, и он работает (ОК, иногда вендорные префиксы ставлю, но вскорее после выхода версии, которая поддерживает работу без префиксов убираю их). А если пользователь сознательно не обновляется — это его проблемы, всем не угодишь и за глюками всех версий не угонишься.
            –2
            Обновите плз IE8 до IE9 в Windows XP, который, несмотря на заканчивающиеся сроки поддержки, до сих пор широко используется в корпоративных системах.

            PS: почему при этом админы не ставят других нормальных браузеров — вопрос не ко мне, но чаще всего кроме IE в корпоративном секторе нет других браузеров.
              0
              Вы сами выбрали свою печальную судьбу.
                0
                Просто не все работают в IT. И да, спасибо за минус в карму.
                  0
                  PS: сам я пользуюсь Chrome-ом. Мне сотрудников жалко
                    0
                    Я вообще не трогал ни карму ни комменты, так что ваш наезд беспочвенный.
                    Просто не надо поддерживать IE8-. ВСЕМ программистам забить на его поддержку. И тогда не будет IE8-
                      0
                      Есть люди, которые и рады не поддерживать его, не используя, но как минимум IE8 вошёл прочно в жизнь по вышеозначенной мной причине.
                      Про карму извините.
              0
              а на сколько вас не беспокоят IE < 9?

              Не беспокоят вообще, потому JS-аксессоры, Canvas, CSS3, etc — это всё ежедневные будни моей работы))
            +3
            Если память не изменяет, то в IE при включении свойства hasLayout (без которого фильтр работать не будет) перестает работать overflow: visible (всё работает в режиме hidden).
            То есть это не баг в прямом смысле этого слова, а эдакая багофича.

            А вообще выше правильно написали: для старых браузеров просто жертвуйте декоративными излишествами (гладиентами, тенями, скруглениями). Там это не нужно и только добавляет тормозов и проблем. Придерживайтесь принципа graceful degradation.
            • UFO just landed and posted this here
                0
                Если вопрос ко мне, то вы сами на него ответили так, как ответил бы я. Пост не о том как сделать градиент при помощи CSS в старых IE, а о занятном баге, который может возникнуть при их использовании.
                • UFO just landed and posted this here
                • UFO just landed and posted this here
                  0
                  Тоже фиксил этот баг Twitter Bootstrap.
                    0
                    IE 7-8 сами по себе вызывают недоумение… Багов хватает и в более поздних версиях, вот только зачем ворошить ПО лет минувших?..
                      0
                      Фильтр для создания градиента, как и все реализации не поддерживаемых CSS правил в старых IE, обрабатывается при помощи JavaScript, а лишний JS сулит ошибками.

                      Ну фильтры, да очень сильно тормозят работу браузера. И в некоторых случаях принцип graceful degradation полезен даже для IE9. А что вы скажете,. к примеру, на счет библиотек типа selectivizr для поддержки css3 селекторов? Просто в ходе работы не замечалось сильных тормозов (возможно из-за недостаточности тестирования).

                      Only users with full accounts can post comments. Log in, please.