最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - css3pie messes up DOM, results in jQuery selector errors - Stack Overflow

programmeradmin2浏览0评论

In order to get CSS3 effects (border-radius, box-shadow...) on IE 6/7/8, I'm using css3pie.

However, css3pie generates some css3-container (v1) / css3pie (v2) tags in DOM, which disorders the expected architecture. Here is an example:

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

The actual generated source is like this:

<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>

Has anyone encountered this kind of problems? Any workaround? Is there an alternative to css3pie to get CSS3 working on IE 6/7/8?

In order to get CSS3 effects (border-radius, box-shadow...) on IE 6/7/8, I'm using css3pie.

However, css3pie generates some css3-container (v1) / css3pie (v2) tags in DOM, which disorders the expected architecture. Here is an example:

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

The actual generated source is like this:

<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>

Has anyone encountered this kind of problems? Any workaround? Is there an alternative to css3pie to get CSS3 working on IE 6/7/8?

Share Improve this question edited Feb 5, 2013 at 12:50 user1643156 asked Feb 5, 2013 at 1:06 user1643156user1643156 4,54711 gold badges41 silver badges59 bronze badges 1
  • It's not worth it. IE 6 and 7 are not supported by Microsoft, so why would you want to support them 100%? :) But seriously - are rounded corners that important for people using a browser that most of the internet looks bad in anyway? Making it work with rounded corners will hurt performance and might make the site unusable in old IEs. – naugtur Commented Feb 13, 2013 at 16:53
Add a ment  | 

5 Answers 5

Reset to default 3 +50

I tried using CSS3PIE too, and faced similar problems (mostly with jquery and mediaqueries). I found no easy/practical solution for all the problems it causes, indeed.

My advice would be to use Modernizr's load to progressively enhance older IE's user experience. It requires an harder/longer process, as you've to setup a single polyfill for each and every CSS3 feature. As mario.tco already told you, there's a list of cross-browser polyfills on Modernizr's repo. And here's a list of feature detection snippets.

Also have a look at html5please and caniuse.

In regard to IE6 and 7, unless your site statistics indicate something different, usage rates are below 1% on average (with some exceptions, check ie6countdown), so you can almost ignore them. However, with conditional ments you can target each IE<10 version with specific fallbacks.

Keep in mind that you don't really need to have box-shadows and other visual decorations (unless they are needed for usability) on IE<9. Indeed, any fallback will probably cause a huge performance problem (think about what hardware an IE7 user could have). Websites don't need to look exactly the same in any browser.

CSS3PIE is a very useful and powerful way to simulate CSS3 rounded corners - and in my pany it is the one that we chose, but there are many other ways to do it.

The way CSS3PIE creates the rounded corners it will create the <css3-container> tag as the previous sibling to the element that has the behavior attribute, so it will change DOM structure and break your prev() calls. The css-container is important because it is a VML drawing of the rounded corner background behind your <pre> tag.

One way you could do this would be to wrap your <pre> tag in something else like a <div> and then use that <div> to navigate the DOM using the prev() function.

Another way you could do this would be to create a jQuery plugin like this

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

Now the following should work like you wanted it to in all browsers.

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

Have you tried this:

http://blog.reybango./2010/10/11/how-polyfills-fill-in-the-gaps-to-make-html5-and-css3-usable-today/

Here is a list of polyfills you can use for other features:

https://github./Modernizr/Modernizr/wiki/HTML5-Cross-browser-Polyfills

This is probably not the answer you're looking for, but instead of trying to get jQuery to ignore PIE's injected elements, I remend (re)writing your jQuery to use classes / IDs more and be less dependent on page structure. This has the benefit of making your code more resilient against other page structure changes, as well as making your code a bit more portable and reusable.

When you must traverse the DOM, most (if not all) of jQuery's traversal methods include a filter selector argument that you can use to exclude PIE's elements, for example:

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

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

Instead of just using the raw prev() add a CSS selector to it to narrow down the search

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

If you are going to use a CSS3 "hack" to make IE 6/7/8 behave correctly don't try and rely on expected DOM structure when walking the DOM try to be more specific.

EDIT

changed the prev() function call to prevUntil()

发布评论

评论列表(0)

  1. 暂无评论