Telling CSS3PIE about dynamic elements

I love CSS3PIE. I love that I can make use of some of the CSS3 niceties like rounded corners and box shadow, and even IE7 and IE8 can keep up with the more modern browsers and not look too shabby. But if you’re adding or moving elements around on your page dynamically, e.g. changing something from display:block to display:none and back, sometimes PIE can’t keep up and leaves a box shadow in a strange place.

But you can easily tell PIE that something has changed, by firing off an event from your JavaScript. According to the documentation, PIE listens for onmove and onresize events to try to keep its custom decorations in the right places and at the right sizes. So, if it isn’t able to detect the change itself, then you just need to fire off an onmove or onresize event of your own. It doesn’t even have to be the element that has the PIE effect, as long as PIE can catch that event when it bubbles up the DOM tree.

element.fireEvent("onmove");

So where have I used this? Here’s two use cases I found for it so far:

  • showing a hidden button on a page dynamically, with PIE border radius support
  • hide/show some content, which rearranges some elements and requires PIE to move its VML objects with them

Maybe there’s a better way, but I did fiddle around with the lazy-poll settings and it didn’t seem to help. This way works flawlessly.

[edit: I've had some feedback that this needs more examples]

Here’s a real example from a website I’ve been working on. I use jQuery UI for a few things on this website, including a fancy looking tabbed display. I also have CSS to make input fields have rounded corners using border-radius. But CSS3PIE misplaces the VML object for the border-radius on the input field on a tab that is initially hidden, so I have to tell it where that input field is when the tab is selected.

$("#searchTabs").tabs({
    show: function(event, ui) {
        // CSS3PIE misplaces the position of the product_name field,
        // because it's initially hidden
        if (window.PIE) {
            document.getElementById("product_name").fireEvent("onmove");
        }
    }
});

On the same website, I have a script that dynamically creates a DIV so that I can add a fancy tooltip to some ABBR elements, because the client wants italics and subscript/superscript text in the tooltips. Because the DIV isn’t on the page at the time CSS3PIE attaches itself to objects with the PIE “behavior”, PIE doesn’t know about it. But that’s OK, I just need to tell PIE to pick it up.

var tooltip = document.createElement("DIV");
var abbrTerms = []; // populated via AJAX, elsewhere

// find the tooltip HTML in abbrTerms, and show the tooltip
function showTooltip(event) {
    var style = tooltip.style,
        a = abbrTerms[this.textContent || this.innerText];

    if (a) {
        style.visibility = "hidden";
        tooltip.innerHTML = a.title;
        style.left = (event.pageX + 15) + "px";
        style.top = (event.pageY + 15) + "px";
        style.visibility = "visible";
    }
}

// hide tooltip when mouse moves away
function hideTooltip() {
    tooltip.style.visibility = "hidden";
}

// move the tooltip when the mouse moves
function moveTooltip(mouse) {
    var style = tooltip.style;
    style.left = (mouse.pageX + 15) + "px";
    style.top = (mouse.pageY + 15) + "px";
}

// show fancy formatted tooltip when hovering over abbr
// NB: I use CSS to style the tooltip nicely, elsewhere
tooltip.id = "abbrTooltip";
tooltip.className = "js-tooltip";
tooltip.style.top = "0";
tooltip.style.visibility = "hidden";
tooltip.style.position = "absolute";
document.body.appendChild(tooltip);

// pick up any CSS3 styles in IE, e.g. rounded corners
if (window.PIE) {
    tooltip.style["-pie-poll"] = false;
    PIE.attach(tooltip);
}

// attach event handlers to the abbr tags
$("abbr.my-product")
    .mouseover(showTooltip)
    .mouseout(hideTooltip)
    .mousemove(moveTooltip);

Job is done, on the run.

facebooktwittergoogle_plusredditpinterestlinkedinmailfacebooktwittergoogle_plusredditpinterestlinkedinmail
  • http://css3pie.com Jason

    Thanks for this article! It’s a good tip.

    • http://snippets.webaware.com.au/ rmckay

      G’day Jason, thanks for an outstanding tool to help drag IE along as we move into a CSS3 world!

  • http://gregbabula.com Greg

    Fantastic read, thanks for sharing

  • Khushbu Bhatia

    Hi,

    I would like to know, what can be done if we are hiding and displaying an element through css. that is css:hover.

    Is there any mechanism that we can inform pie about a display:block or display:none style change through css it self.

    I would appreciate your help

    Thanks

    • http://snippets.webaware.com.au/ rmckay

      For that, I think the recommended practice is to hook PIE to the element without the :hover and then PIE will pick it up on hover. But you’ll get better answers if you ask on the CSS3PIE forums.

      • Khushbu Bhatia

        Thanks rmckay, It worked for me. Thank u very much.
        I just need to ask one question that is CSS3 PIE good enough for practical implementations as I am planning to use it for one of my projects. Are there any side effects of it like performance compromise, or anything else, that I should take care of.

        • http://snippets.webaware.com.au/ rmckay

          Yes, and yes. I use it on several websites, but sparingly and judiciously. It does have a performance impact, which increases with the number of elements you attach it to, and especially on IE8/9 where it needs to poll each attached element every quarter-second to see whether it has moved or resized. However, I use it only for IE7/8 and only where I can’t make use of IE-specific CSS such as filters.

          e.g. IE’s filters can be used to make simple linear gradient backgrounds with two colours, so I often just use that instead of PIE. However, if I need to blend three colours, or if the element needs rounded corners and gradient background, I use PIE (or evaluate whether IE7/8 really needs to equal the other browsers!)

          I don’t use PIE for IE9 because the only feature I’d want it for is linear gradients, and I can achieve that with SVG background images. This means IE9 performs at its top speed, whereas IE7/8 is a little slower but at least fully functional.

          cheers,
          Ross

  • Matt

    This doesn’t seem to work for me. I just get told that .fireEvent is not a function. I’m having trouble with my popup window’s PIE styling being messed up or taking a second to correct itself after the first time it has appeared and been dismissed.

    • http://snippets.webaware.com.au/ Ross McKay

      fireEvent is a method on elements in IE. Are you trying to call it from a jQuery object or something like that? Post your code somewhere like pastebin so that I can diagnose it.

      cheers,
      Ross

      • Matt

        I can’t get there from work.
        You are correct. I realized I needed to add [0] but that has only stopped the errors. It doesn’t seem to be having any effect.


        if (self.popup.is(':hidden')) {
        if ($(self.popupsAll + ':visible').length === 0) {
        self.popup.fadeIn(300);
        self.popup[0].fireEvent('onmove');
        } else {
        self.friends.fadeOut(300);
        self.popup.delay(400).fadeIn(300);
        self.popup[0].fireEvent('onmove');
        }
        }

        popup is the popup that is supposed to display.

        [ed: formatted code]

        • http://snippets.webaware.com.au/ Ross McKay

          Ha, I optimistically wrapped your code in the code tags, but still no indent :)

          First point, maybe niggly, but: wrap your fireEvent calls in a test to see if you’re running PIE, so it doesn’t trigger an error on non-IE browsers:

          if (window.PIE) { ... }

          Now, I’m guessing that the fireEvent is happening too soon before jQuery’s animation starts making the popup visible and hence the position isn’t correctly detected. As to what to do about that: not sure, perhaps you can try setting display:block and opacity:0.01 or something, so that PIE can detect that it should be shown, then call fireEvent, then do your fadeIn. Let me know what you find (as others will probably want to know too!)

          cheers,
          Ross

          • Aurelien

            Hey,

            I’m having a similar if not exact same issue.
            I have a form with a round-bordered div (.cpButton) at the bottom. This “button” acts as a submit button.
            When the cpButton is clicked and the form is invalid, some error messages appear below the input fields, but the round-bordered div’s position is not updated correctly.

            I have come up with a solution, but the button briefly blinks (disappears then reappears)

            if (window.PIE) {
            $(‘.cpButton’).each(function(i, el) {
            $(el).css(‘display’, ‘none’);
            setTimeout(function() {
            $(el).css(‘display’, ‘block’);
            }, 1)
            });
            }

            I tested it in IE78 with success

            This solution is somewhay crappy, so any better solution would be greatly appreciated!
            In the meantime, I hope my solution can help.
            Cheers

          • Matt

            I tried calling this after the fadein. I put in the delay so that it would in the middle of the fadein. Unfortunately now the popups become permanent. Even my click event on the popup to close it doesn’t work.


            pieCorrection: function(){
            var self = this;
            if (window.PIE) {
            self.popup.delay(100, function(){
            self.popup[0].fireEvent('onmove');
            });
            }
            },

  • Decebalus Rex

    WOW this is really nice, thank you for this article. I have a drop-down menu that gives me headache.Maybe some one can help me with this. With this function I apply pie to my elements:
    (document).ready(function(){
    if (window.PIE) {
    $(‘ul#menu,ul#menu li ul’).each(function(){
    PIE.attach(this);
    });
    }

    });
    but on hover, when pie apply border-radius and box shadow on the expanded menu, the background is not displayed well how can you see in this picture:

    http://s9.postimage.org/61buariu6/untitled.jpg

    Sometimes is well displayed and if I play a little bit with my menu I have this problem :|

    This is the css:

    ul#menu {
    height: 52px;
    margin: 5px 0 0;
    list-style-type: none;
    border-color: #f4f4f4 white white;
    border-style: solid;
    border-width: 1px;
    border-radius:30px;
    background:none;
    }

    ul#menu li:hover ul{
    display:block;
    background: #f8f8f8;
    border-radius:0 8px 8px 8px;
    box-shadow: 0px 5px 7px 5px #eaeaea;
    }

    • http://snippets.webaware.com.au/ Ross McKay

      G’day, you should probably try asking for help on the CSS3PIE forums rather than a blog, you’ll get more help there.

  • Ronny

    The fireEvent did not work for me but this did.

    if (window.PIE) { // IE8
    var filter = $("#filterPIE");
    filter.hide();
    setTimeout(function() {filter.show();}, 0);
    // document.getElementById("filterPIE").fireEvent("onmove");
    }