
Fixed-position elements and mispaced PIE rendering
Hi all.
I'm not sure this is the right forum for this, considering that I've got a problem and potential solution at the same time. Does already shot trouble go in trouble-shooting or not?
Anyway, having tried out PIE to give me border-image support in IE, I discovered that my borders and background were being drawn in the wrong position when the styled element had position: fixed. Specifically, the element in question was an immediate child of the body; I suspect the problem would not have occurred, or would have manifested differently, had that element been contained in another absolutely-positioned element.
So I dived into the PIE code to figure out what was going wrong. I discovered that PIE did not correctly calculate the position of position: fixed elements, only for elements positioned with respect to some positioned parent element.
So I changed the updatePos function of PIE.RootRenderer, and my tests so far show it to be working for me. Here's my version of the function...
Code:
updatePos: function() {
if (this.isActive()) {
var el = this.element,
par = el,
docEl,
elRect, parRect,
s = this.getBox().style, cs,
x = 0, y = 0;
// Get the element's offsets from its nearest positioned ancestor. Uses
// getBoundingClientRect for accuracy and speed.
do {
par = par.offsetParent;
} while (par && par.currentStyle.position === 'static');
elRect = el.getBoundingClientRect();
if (par) {
parRect = par.getBoundingClientRect();
cs = par.currentStyle;
x = elRect.left - parRect.left - (parseFloat(cs.borderLeftWidth) || 0);
y = elRect.top - parRect.top - (parseFloat(cs.borderTopWidth) || 0);
} else {
docEl = el.document.documentElement;
x = elRect.left - docEl.clientLeft;
y = elRect.top - docEl.clientTop;
if (el.currentStyle.position !== 'fixed') {
x += docEl.scrollLeft;
y += docEl.scrollTop;
}
}
s.position = el.currentStyle.position === 'fixed' ? 'fixed' : 'absolute';
s.left = x;
s.top = y;
s.zIndex = el.currentStyle.position === 'static' ? -1 : el.currentStyle.zIndex;
}
},
Notice that I've set the position of PIE's element to be fixed if it is to sit behind a fixed element, and in such a case the document scrollLeft and scrollTop are not used to calculate position.
I have not, however, done anything about getting the positions right for IE6 (or earlier). IE6 treats position: fixed as position: absolute, which means that this would now produce an incorrect result in IE6 whereas before it would have worked (for a given value of "worked") in that browser. I figure for my current purposes, I don't care enough about IE6 to ensure that it gets the prettiest possible borders (no loss of functionality, just a little aesthetics, for that site), and if I did want to do something about it the best fix would probably to use conditional comments to produce an IE6-only stylesheet that replaces all the position: fixed CSS into position: absolute, so that the CSS matches the actual effect and PIE doesn't get fooled. (Or alter the styles with a quick bit of jQuery magic - after all, if PIE works, so does javascript, and since I've used some jQuery anyway...)
Now, I'll just build my own version of PIE to incorporate the fix, and I think I'm good to go.
So, can anyone guess at problems I might have missed? Either that my fix hasn't covered, or that I may have introduced with my fix? I'm guessing that there might be issues with fixed-position children of absolutely-positioned elements, but haven't done my testing to check.
And might I suggest that such a change as I've made be incorporated into a future version of PIE? If it's a good solution and hasn't introduced further problems, of course.