Menu

Snippets

Yet another programmer blogging about code

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.