Pull to refresh

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

Reading time 6 min
Views 12K
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. Я не сомневаюсь в том, что помимо описанных ситуаций можно воспроизвести подобные на этой же почве, или наоборот — отыскать иные методы преодоления.

Спасибо за внимание.
Tags:
Hubs:
+13
Comments 23
Comments Comments 23

Articles