为啥伪元素上的过滤器渐变在 IE8 中不起作用?

Posted

技术标签:

【中文标题】为啥伪元素上的过滤器渐变在 IE8 中不起作用?【英文标题】:Why does a filter gradient on a pseudo element not work in IE8?为什么伪元素上的过滤器渐变在 IE8 中不起作用? 【发布时间】:2012-05-11 08:19:39 【问题描述】:

我想创建这样的按钮:

在现代浏览器中,效果是使用插入框阴影和滤镜创建的。 对于 IE8 - 选择伪元素。 对于 IE7 - 我使用包含在条件 cmets 中的特殊标签。

演示: (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>

主要问题:为什么过滤器对 IE8 中的伪元素不起作用?


更新:

我猜过滤器不适用于 css 生成的内容,尽管 MSDN page 中没有提到它。

我通过将过滤器应用于条件元素来解决我在 IE8 中的问题,就像我在 IE7 中所做的那样。

最终演示: (http://jsfiddle.net/matmuchrapna/8M5Tt/73/)

/**
 * 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;
    

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

/* 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 lte IE 8]> <span class="before"> </span><span class="after"> </span> <![endif]-->
</button>

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

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

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

</div>

更新 2:

我解决了我的问题,但主要问题仍未得到解答:

“为什么过滤器对 IE8 中的伪元素不起作用?”

开始赏金。

更新 3: 我为 ie8 上的过滤器(以及 -ms-filter)创建了 testcase:

但过滤器仍然不想处理伪元素。

更新 4: 我认为Scotts answer 最接近真相。

【问题讨论】:

真的值得去经历这些麻烦吗? IE 过滤器和伪元素一样有缺陷。我要么使用图像,要么让 IE 做它的事情。用户甚至不会注意到。 +1 表示你的提问风格很好。 只有我一个人每次都在图像的十字路口看到消失的灰点吗? 据我所知,公共 IE8 错误数据库不再可用,因此您的赏金问题可能无法回答“这是一个错误”,除非 IE 团队中的某个人出现并打算分享。 在 IE8 测试期间,微软表示他们将维护一个公共错误数据库,任何人都可以提交错误供微软查看。它……非常有效,但还是有一些不为人知的错误通过了。 【参考方案1】:

问题是“为什么过滤器对 IE8 中的伪元素不起作用?”以下是我所能收集到的最接近明确的答案。它来自this page上的信息。

gradient 过滤器是一个“程序表面”(与alphaimageloader 一起)。程序表面是这样定义的:

程序表面是显示在 对象的内容和对象的背景。

仔细阅读。它本质上是您可以在对象的内容和该对象的背景之间说的另一个“层”。你看到问题的答案了吗? :before:after 创建的内容...是的! 内容。具体为MSDN notes:

::before 和 ::after 伪元素指定 文档树中元素之前和之后的内容。内容 属性与这些伪元素一起指定什么 已插入。

生成的内容与其他盒子交互,就好像它们是真实的一样 元素插入到它们的关联元素中。

现在,如果生成的是content,那么它不是包含内容的“对象”,而是内容本身(恰好有一些类似于可能包含内容的元素对象的行为。

因此,没有“对象”包含“内容”(因为它内容)filter 可以在它们之间放置由一个伪元素(即“假元素”)。必须将gradient 应用于对象,然后将程序表面放置在它和内容之间。

【讨论】:

我注意到 MSDN 交替使用“属性”和“属性”这两个词来描述 content。好的。 @matmuchrapna--好吧,可能没有办法证明我的解释是不是真正的原因,但当我阅读信息时,这对我来说确实是最合乎逻辑的结论。很高兴您同意并满足您对答案的要求。【参考方案2】:

-ms-filter 上的文档-filter 的同义词-指出:

对象必须具有过滤器才能呈现的布局。

我的第一个猜测是 :before 内容没有将 hasLayout 设置为 true。虽然它可能未设置为 true,但可能也未设置为 false。对于初学者,当我按照hasLayout docs 强制内容获取hasLayout = true(请参阅jsfiddle)时,它没有解决任何问题。

所以我会说它既不是真的也不是假的。相反,它可能是未定义。我在同一文档中提到了该属性的来源:

对象.currentStyle.hasLayout

如果我们看一下W3 documentation on the content property,它会说:

生成的内容不会改变文档树。特别是,它不会反馈给文档语言处理器(例如,用于重新解析)。

因此,可能的结论是生成的内容不是对象,因此它没有currentStyle 属性,因此也没有' t 将 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 在 cmets 中提到的:querySelectorAll cannot access pseudo-elements。


在this msdn introduction on filters 中可以找到filter 对伪元素不起作用的另一个提示(虽然-再次-只不过是一个提示),说明(强调我的):

过滤器通过过滤器属性应用于HTML控件

虽然我不确定“HTML 控件”是什么意思,但我不希望 :before 伪元素生成的内容被视为“HTML 控件”。

【讨论】:

关于querySelectorAll() 的部分是红鲱鱼,如it can never access pseudo-elements。自然,伪元素不是 DOM 的一部分。 @BoltClock 啊,当然,谢谢!那么可能没有“干净”的方法来确定生成的内容上是否存在内部 hasLayout 属性。我将编辑问题并将您提到的链接也放在那里。 是否可以通过将zoom:1 应用于伪元素来触发hasLayout?这是一个奇怪的发现,但我无法从我的家用机器访问 IE 框来测试它。 @o.v. AFAIK 没有可靠的方法来找出伪元素的 hasLayout 属性是什么,在我的回答中,我推测它甚至可能没有该属性。无论哪种方式,如果您使用zoom:1 打开this updated version of the jsfiddle,filter 在IE8 中仍然不起作用。 虽然我不同意您的任何其他观点与它有任何关系,但我确实认为当您说“所以,一个可能的结论是生成的内容是不是一个对象。”根据我刚刚发布的答案,我相信这是问题的一半。【参考方案3】:

与其使用 IE 的 filter 样式,您是否考虑过使用 CSS3Pie?

这是一个 IE 脚本,增加了对标准 CSS box-shadow 和渐变的支持,因此您可以在所有浏览器中编写相同的代码,而不必拥有所有那些特定于 IE 的样式。

【讨论】:

它在 inset box-shadow 上失败,并且在没有 javascript 的情况下也无法工作 就个人而言,如果我只关心渐变,我宁愿使用the Ultimate CSS Gradient Generator(支持IE6-9),而不是处理CSS3Pie的额外.js和.htc文件。 @gmeben 我也用这个生成器colorzilla.com/gradient-editor/#ff0000+0,00ff15+100;Custom【参考方案4】:

我已经给出了我喜欢的解决方案(使用 CSS3Pie),但我会将此作为单独的答案发布。

IE8 无法与 IE7 工作的 filter 一起工作的可能原因是 IE8 更改了 filter 的语法。

filter 是一种特定于 IE 的专有样式。当微软发布 IE8 时,他们强调要“符合标准”。支持非标准样式的“符合标准”的方式是给它一个供应商前缀,这就是微软所做的。

因此在 IE8 中,您需要执行以下操作:

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

IE7 不支持这种语法,所以你需要他们两个。

IE8 实际上确实使用旧语法在某些情况下。它不起作用的情况往往是您使用progid: 语法的情况。原因是progid 后面的冒号导致它是无效的CSS 语法,这就是为什么MS 在IE8 -ms-filter 版本的整个thin 周围添加引号的原因。

所以简短的回答是,在你的样式表中使用这两个版本,你会没事的。

【讨论】:

>"IE8 无法与 IE7 工作的过滤器一起工作的可能原因是 IE8 更改了过滤器的语法。"不,因为在这个 demo 选择器 .ie8 .btn:before 上使用正确的 ie8 语法,并且未应用过滤器 我同意@matmuchrapna 的观点,filter 语法不是问题。我相信它是基于伪元素的性质和我在回答中概述的 gradient 过滤器。 我对帖子进行了更新3,证明过滤器在两种语法中都有效 很公平。 IE8 肯定有很多时候更喜欢-ms-filter syntqx,但如果你在这里都可以,那也很好。不过,我会将答案留在原处,以供将来参考。【参考方案5】:

哇,这太难了。

After reviewing this chart,确认IE8 only likes single colons on its pseudo-elements,阅读此possibly related blog article,并做了很多testing in jsFiddle(尽管与您的73 相比,它很少??jsFiddles),我不得不得出结论,这是IE8 中的一个错误。

IE9 可以在伪元素上做渐变(用 base64 废话),但 IE8 被顽固地破坏了。

【讨论】:

IE8 不支持 CSS3 伪元素语法与过滤器首先不能在伪元素中工作没有太大关系,除了整个“IE 是错误的”心态 :) @BoltClock 很好地抓住了元素/选择器编辑。我只是想指出在 IE8 中使用伪元素时所有必要的部分。从理论上讲,当考虑到所有这些部分时,过滤器应该可以工作。他们不这样做的事实让我相信这是一个错误(不一定是因为我有一种心态啊!)。 @gmeben--因为“伪元素”的意思是“假元素”(字面意思),并且因为它被设计为仅用于 content 插入(它在技术上会仅仅内容包含内容本身是一个逻辑矛盾;就像一个苹果包含一个苹果,而不是一个),并且由于IE将它们的程序表面定义为内容和它的对象之间(他们有权定义他们想要的程序表面;它不是 HTML/CSS 规范的一部分),我不确定我是否可以对“设计不佳”进行指控" 在 IE8 上针对这个特定问题(现在,其他问题......)。 @gmeben--是的,“属性”和“属性”的使用不正确。我不确定是否需要放弃“伪元素”。事实上,它不是一个真正的元素。你不能把 html 放进去,就 html 本身而言,它也不存在于 DOM 树中,所以它不是 html 标签意义上的“真实”。生成时,它确实是为了视觉目的,就像一种幻觉——它似乎存在,但实际上并不存在(与“真实”元素具有相同的意义)。 @gmeben——你没抓住重点。不仅仅是 IE 认为它们是“装饰性的”,这就是它们的全部目的。它们纯粹是为了 presentational 使用,这就是为什么它们是 CSS 的一部分,而不是 HTML。初衷只是为了做typographical change。后来,加上:before:after,是为了让generated textual content 也用于演示。此后,网页设计师利用“空白”内容制作了许多简洁的效果。

以上是关于为啥伪元素上的过滤器渐变在 IE8 中不起作用?的主要内容,如果未能解决你的问题,请参考以下文章

如果存在背景颜色,IE8 渐变过滤器将不起作用

jQuery.animate 在 IE8/IE9 上的 Facebook iFrame 中不起作用

overflow-x在IE8中不起作用

在 IE9 中使用 CSS3 PIE 的线性渐变不起作用,IE8 可以

之前和之后的伪元素在顺风 CSS 中不起作用

jQuery *= 选择器在 IE8 中不起作用