6

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?

user1643156
  • 4,407
  • 10
  • 36
  • 59
  • 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 Feb 13 '13 at 16:53

5 Answers5

3

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

Giona
  • 20,734
  • 4
  • 56
  • 68
  • It seems this is an unsolvable problem as long as we want fancy look on old browsers. I have actually removed css3pie from my project, as @naugtur said...it's not worth it. well...I had to choose an answer to accept, and the info you provided seems useful. – user1643156 Feb 14 '13 at 18:12
2

CSS3PIE is a very useful and powerful way to simulate CSS3 rounded corners - and in my company 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));
codefactor
  • 1,616
  • 2
  • 18
  • 41
  • Your plugin does the job to solve this specific `prev` problem. But there are still a whole lot of problems with css3pie, it affects almost all jQuery selectors...e.g. `$("body").children().size()` will return 4 instead of 3 in my example. Writing a plugin to fix all these errors doesn't seem to be a perfect solution. – user1643156 Feb 05 '13 at 12:43
  • Yes, in general I've learned it is not a good idea to use these types of selectors when using css3pie. When testing your code just make sure you test IE every time because of these issues. One thing you might want to do is provide class names on most elements that you need to find or count, and use these class names in your selector so it will always work regardless of these extra css3-container elements. – codefactor Feb 12 '13 at 17:03
  • Thanks for replying, codefactor. But the problem is that sometimes we don't known the id/class, the prev element might be totally unknown. As for round corner and shadow, I could instead do some extra work to write a plugin using images for IE 6/7/8, but it's really not that desperate. So until someone comes up with a perfect solution, I guess I'll have to drop css3pie from my application. – user1643156 Feb 12 '13 at 17:33
  • @user1643156 don't hold your breath for a perfect solution that doesn't affect the DOM structure. All other automated ways to achieve rounded corners on non-CSS3 browsers that I've seen change the DOM structure in some way. You'll never have a perfect rounded corner solution on non-CSS3 browsers without some extra elements being added. Otherwise you'll be forced to change your HTML markup and not use CSS3 at all so the DOM structure is the same in all browsers. – codefactor Feb 13 '13 at 21:53
2

Have you tried this:

http://blog.reybango.com/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.com/Modernizr/Modernizr/wiki/HTML5-Cross-browser-Polyfills

mario.tco
  • 674
  • 1
  • 7
  • 19
1

This is probably not the answer you're looking for, but instead of trying to get jQuery to ignore PIE's injected elements, I recommend (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)')
Jeffery To
  • 11,836
  • 1
  • 27
  • 42
0

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

Geek Num 88
  • 5,264
  • 2
  • 22
  • 35
  • `prev('p')` or `prev('.paragraph')` will **not** work because `jQuery reference: prev() - Get the **immediately** preceding sibling...` should be using `prevUntil`. But...what if the prev element is unknown? – user1643156 Feb 05 '13 at 01:46
  • thanks for pointing that out - I updated my answer - in this instance I think you might need to depend less on the DOM structure if it is going to be changed before you get to act on it. – Geek Num 88 Feb 05 '13 at 17:49