Подтвердить что ты не робот

Почему градиент фильтра на псевдоэлементе не работает в IE8?

Я хочу создать такие кнопки:
псевдо 3d кнопка

В современных браузерах эффект создается с помощью вставки-тени и фильтров.
Для IE8 выбраны псевдоэлементы.
Для IE7 - я использую специальные теги, завернутые в условные комментарии.

Демо: (http://jsfiddle.net/8M5Tt/68/)

/**
 * Button w/o images
 */
html {
    font-size: 62.5%;
    }
body {
    font: normal 1em/1em Arial, Tahoma, Verdana, sans-serif;
    }
 
/* layout */
.btn {
    display: inline-block;
    height: 28px;
    border-width: 1px;
    border-style: solid;
    width: 170px;
    box-sizing: content-box;
    overflow: hidden;
    position: relative;
    z-index: 1;
    }
.btn {
    margin: 15px;
    }
.btn.btn_small {
    width: 130px;
    }

/* ie7 */
.lt-ie8 .btn .before,
.lt-ie8 .btn .after {
    position: absolute;
    right: -1px;
    left: -1px;
    display: block;
    height: 3px;
    }
.lt-ie8 .btn .before {
    top: -1px;
    filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#80ffffff', endColorstr='#00ffffff',GradientType=0 );
    }
.lt-ie8 .btn .after {
    bottom: -1px;
    filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#00ffffff', endColorstr='#80000000',GradientType=0 );
    }
/* /ie7 */

/* ie8 */
.ie8 .btn:before,
.ie8 .btn:after {
    content: ' ';
    z-index: 1;    
    position: absolute;
    right: -1px;
    left: -1px;
    display: block;
    height: 3px;
    }
.ie8 .btn:before {
    top: -1px;
    filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#80ffffff', endColorstr='#00ffffff',GradientType=0 );
    }
.ie8 .btn:after {
    bottom: -1px;
    filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#00ffffff', endColorstr='#80000000',GradientType=0 );
    }
/* /ie8 */

/* typo */
.btn {
    /* 28 / 14 = 2.57142857 */
    font: bold 14px/2 Arial, Helvetica, Tahoma, sans-serif;
    text-transform: uppercase;
    }
.btn:active {
    line-height: 2.4em;
    }

/* color */
.btn {
    background-color: #00cccc;
    color: #fff;
    border-color: #00a8a8;
    border-radius: 3px;
    cursor: pointer;
    box-shadow:
         1px  1px 4px rgba(255, 255, 255, 0.5) inset,            
        -1px -1px 4px rgba(000, 000, 000, 0.5) inset;
    }
.btn:hover {
    background-color: #00ebeb;
    }
.btn:active {
    box-shadow:
        -1px -1px 4px rgba(255, 255, 255, 0.5) inset,            
         1px  1px 4px rgba(000, 000, 000, 0.5) inset;
    }

/* green */
.btn_green {
    background-color: #009900;
    border-color: #009600;
    }
.btn_green:hover {
    background-color: #00c200;
    }

/* red */
.btn_red {
    background-color: #e00000;
    border-color: #c13d00;
    }
.btn_red:hover {
    background-color: #f00000;
    }
<!--
paulirish.com/2008/conditional-stylesheets-vs-css-hacks-answer-neither/
-->
<!--[if lt IE 7]> 
    <div class="no-js lt-ie9 lt-ie8 lt-ie7" lang="en">
<![endif]-->
<!--[if IE 7]>
    <div class="no-js lt-ie9 lt-ie8 ie7" lang="en">
<![endif]-->
<!--[if IE 8]>
    <div class="no-js lt-ie9 ie8" lang="en">
<![endif]-->
<!--[if gt IE 8]><!-->
    <div class="no-js no-ie" lang="en">
<!--<![endif]-->

<button class="btn btn_green btn_small ">
    Send
    <!--[if IE 7]> <span class="before"> </span><span class="after"> </span> <![endif]-->
</button>

<button class="btn">
    Buy
    <!--[if IE 7]> <span class="before"> </span><span class="after"> </span> <![endif]-->
</button>

<button class="btn btn_green">
    Activate
    <!--[if IE 7]> <span class="before"> </span><span class="after"> </span> <![endif]-->
</button>

<button class="btn btn_red">
    Delete
    <!--[if IE 7]> <span class="before"> </span><span class="after"> </span> <![endif]-->
</button>

</div>
4b9b3361

Ответ 1

Вопрос: "Почему фильтры не работают с псевдоэлементами в IE8?" Следующее как можно ближе к окончательному ответу, который я могу собрать. Он исходит из информации на этой странице.

Фильтр gradient является "процедурной поверхностью" (вместе с alphaimageloader). Процедурная поверхность определяется так:

Процедурные поверхности - это цветные поверхности, которые отображаются между содержимого объекта и фона объекта.

Прочтите это внимательно. Это, по сути, еще один "слой", который вы можете сказать между содержимым объекта и фона этого объекта. Вы видите ответ на вопрос? Что создано :before и :after... Да! Содержание. В частности, как примечания MSDN:

Элементы:: before и:: после псевдоэлементов определяют местоположение до и после элемента в дереве документов. Контент атрибут в сочетании с этими псевдоэлементами указывает, что вставляется.

Сгенерированный контент взаимодействует с другими блоками, как если бы они были реальными элементы, вставленные только внутри их связанного элемента.

Теперь, если это контент, который сгенерирован, то он не является "объектом", содержащим контент, а сам контент (который, случается, имеет какое-то поведение, подобное объекту элемента, которое может содержать контент).

Таким образом, нет "объекта", содержащего "контент" (поскольку он является содержимым), между которыми filter может размещать процессуальную поверхность для контента, генерируемого псевдоэлементом (т.е. "ложный элемент" ). A gradient должен быть применен к объекту, а затем процедурная поверхность помещается между ним и контентом.

Ответ 2

Документация на -ms-filter - синоним для filter - заявляет:

Объект должен иметь макет для рендеринга фильтра.

Мое первое предположение заключалось в том, что для содержимого :before не установлено hasLayout значение true. И хотя он, вероятно, не установлен в true, он, вероятно, тоже не установлен в false. Во-первых, когда я следил за документами hasLayout, чтобы заставить контент получать hasLayout = true (см. jsfiddle) он ничего не решал.

Поэтому я бы сказал, что это не правда и не ложно. Вместо этого, вероятно, undefined. Я отметил в тех же документах, что он говорит об источнике этого свойства:

объект .currentStyle.hasLayout

Если мы посмотрим на документацию W3 по свойству содержимого, в нем говорится:

Сгенерированный контент не изменяет дерево документа. В частности, он не возвращается обратно на процессор языка документа (например, для повторной обработки).

Итак, возможный вывод заключается в том, что сгенерированное содержимое не является объектом, поэтому оно не имеет свойства currentStyle и, следовательно, также не имеет hasLayout, установленного в true. Это было бы причиной того, что фильтры не работают с созданным контентом и, таким образом, отвечают на вопрос.


На первый взгляд я думал, что нашел подсказку в консоли вышеупомянутой скрипки:

document.querySelectorAll('div')[0].currentStyle.hasLayout; 
// true

document.querySelectorAll('div:before')[0].currentStyle.hasLayout
// Unable to get value of the property 'currentStyle': 
// object is null or undefined

Но, как упоминалось в комментариях @BoltClock: querySelectorAll не может получить доступ к псевдоэлементам.


Еще один намек (хотя -агаин - не более, чем подсказка), что filter не будет работать на псевдоэлементы, можно найти в в этом msdn в фильтрах, заявив (акцент мой):

Фильтры применяются к элементам управления HTML через свойство фильтра

Хотя я не уверен, что подразумевается под "HTML-элементами управления", я бы не ожидал, что контент, сгенерированный псевдоэлементом :before, будет считаться "HTML-контролем".

Ответ 3

Вместо того, чтобы использовать стиль IE filter для этого, рассмотрели ли вы использование CSS3Pie?

Это script для IE, который добавляет поддержку стандартного CSS box-shadow и градиентов, поэтому вы можете написать один и тот же код во всех браузерах, а не иметь все эти стили, специфичные для IE.

Ответ 4

Я уже дал свое предпочтительное решение (используйте CSS3Pie), но я отправлю его как отдельный ответ.

Вероятная причина, по которой IE8 не работает с filter, где работает IE7, заключается в том, что IE8 изменил синтаксис filter.

filter - это особый проприетарный стиль. Когда Microsoft выпустила IE8, они сделали большой шаг к тому, чтобы быть "стандартами". "Стандартно-совместимый" способ поддержки нестандартного стиля - предоставить ему префикс поставщика, и именно это и сделала Microsoft.

Итак, поэтому в IE8 вам нужно сделать следующее:

-ms-filter: "progid:DXImageTransform.Microsoft.gradient( startColorstr='#80ffffff', endColorstr='#00ffffff',GradientType=0 )";

IE7 не поддерживает этот синтаксис, поэтому вам нужны оба.

IE8 действительно работает со старым синтаксисом в некоторых случаях. Случаями, когда он не работает, как правило, являются те, в которых вы используете синтаксис progid:. Причина этого в том, что двоеточие после progid вызывает недопустимый синтаксис CSS, поэтому MS добавляет котировки вокруг всего тонкого для версии IE8 -ms-filter.

Итак, короткий ответ: используйте обе версии в своих таблицах стилей, и все будет в порядке.

Ответ 5

Ничего себе, это тяжело.

После просмотра этой диаграммы, подтверждающей, что IE8 любит только одиночные двоеточия его псевдоэлементы, читая эту возможно связанную статью в блоге и делая много тестирование в jsFiddle (хотя это немного по сравнению с вашими 73?? jsFiddles), мне пришлось бы сделать вывод, что это ошибка в IE8.

IE9 может выполнять градиенты на псевдоэлементах (с бестселлером base64), но IE8 упрямо нарушен.