css3pie搞砸了DOM,导致jQuery选择器错误

时间:2013-02-05 01:06:55

标签: javascript jquery css3 css3pie

为了在IE 6/7/8上获得CSS3效果(border-radius,box-shadow ...),我正在使用css3pie

然而,css3pie在DOM中生成了一些css3-container (v1) / css3pie (v2)标记,这会使预期的体系结构失调。这是一个例子:

CSS

pre {
    border: 1px solid #aaa;
    border-radius: 5px;
    behavior: url(pie.htc);
}

HTML

<div class="foo">bar</div>
<p class="getme">paragraph</p>
<pre>preformatted</pre>

的jQuery

// undefined        expected: getme
alert($("pre").prev().attr("class"));

// css3-container   expected: p
alert($("pre").prev()[0].tagName);

// getme            expected: foo
alert($("pre").prev().prev().attr("class"));

// 4                expected: 3
alert($("body").children().size());

// will not set     expected: Impact
$("p+pre").css({fontFamily: "Impact"});

// it almost affects all such jQuery selctors

实际生成的源是这样的:

<DIV class="foo">bar</DIV>
<P class="paragraph">paragraph</P>
<css3-container...>
    <border...>
        <shape...><stroke></stroke><stroke></stroke></shape>
    </border>
</css3-container>
<PRE>preformatted</PRE>

有没有人遇到过这种问题?任何解决方法?有没有css3pie的替代方案让CSS3在IE 6/7/8上工作?

5 个答案:

答案 0 :(得分:3)

我也尝试使用CSS3PIE,并遇到类似的问题(主要是使用jquery和mediaqueries)。事实上,我找不到它导致的所有问题的简单/实用的解决方案。

我的建议是使用Modernizr's load逐步增强旧IE的用户体验。它需要更难/更长的过程,因为您需要为每个CSS3功能设置单个polyfill。正如 mario.tco 已经告诉过你,在Modernizr的回购中有一个list of cross-browser polyfills。以下是feature detection摘要列表。

另请查看html5pleasecaniuse

关于IE6和7,除非您的网站统计信息显示不同的内容,否则使用率为below 1% on average(有一些例外,请检查ie6countdown),因此您几乎可以忽略它们。但是,使用conditional comments,您可以针对具有特定回退的每个IE&lt; 10版本进行定位。

请记住,您并不需要在IE&lt; 9上真正需要盒子阴影和其他视觉装饰(除非它们是可用性需要的)。实际上,任何后备都可能会导致巨大的性能问题(想想IE7用户可能拥有的硬件)。 Websites don't need to look exactly the same in any browser

答案 1 :(得分:2)

CSS3PIE是一种非常有用且强大的模拟CSS3圆角的方法 - 在我的公司中它是我们选择的那个,但还有很多其他方法可以做到。

CSS3PIE创建圆角的方式将创建<css3-container>标记作为具有behavior属性的元素的前一个兄弟,因此它将更改DOM结构并中断prev()调用。 css容器非常重要,因为它是<pre>标记后面圆角背景的VML图。

您可以这样做的一种方法是将<pre>标记包含在<div>之类的其他内容中,然后使用<div>使用prev()导航DOM功能

你可以这样做的另一种方法是创建一个这样的jQuery插件

/* This adds a plugin prevPie and nextPie - it is the same as the
   existing prev and next, but it will ignore css3-containers. */
(function($){
    function addPlugin(name) {
        $.fn[name + 'Pie'] = function() {
            var result = [];
            this[name]().each(function(i,el){
                if (el.tagName == 'css3-container') {
                    var val = $(el)[name]()[0];
                    val && result.push(val);
                } else {
                    result.push(el);
                }
            });
            return $(result);
        }
    }
    addPlugin('prev');
    addPlugin('next');
})(jQuery);

现在,以下内容应该像您在所有浏览器中一样工作。

// undefined        expected: getme
alert($("pre").prevPie().attr("class"));
// css3-container   expected: p
alert($("pre").prevPie()[0].tagName);

// getme            expected: foo
alert($("pre").prevPie().prevPie().attr("class"));
// P                expected: div
alert($("pre").prevPie().prevPie()[0].tagName));

答案 2 :(得分:2)

答案 3 :(得分:1)

这可能不是您正在寻找的答案,但我建议(重新)编写您的jQuery以更多地使用类/ ID,而不是试图让jQuery忽略PIE的注入元素。减少对页面结构的依赖。这样做的好处是使您的代码能够更好地抵御其他页面结构更改,并使您的代码更具可移植性和可重用性。

当您必须遍历DOM时,大多数(如果不是全部)jQuery's traversal methods都包含一个过滤器选择器参数,可用于排除PIE的元素,例如:

$("pre").prevUntil('*', 'not(css3-container)')

$("body").children('not(css3-container)')

答案 4 :(得分:0)

不是仅仅使用原始prev()添加CSS选择器来缩小搜索范围

$("pre").prevUntil('p').attr("class");
// OR
$("pre").prevUntil('.paragraph').attr("class");

如果您打算使用CSS3“hack”来使IE 6/7/8正常运行,那么在走DOM时尝试依赖于预期的DOM结构会尝试更具体。

修改

prev()函数调用更改为prevUntil()