Reputation: 60463
I'm trying to create some kind of masking animation where an image is revealed from its center (edit: "center" doesn't necessarily mean the center of the actual background image, but the center of the visible area! /edit). It's working fine so far, the only problem is that in Chrome (currently 24.0.1312.52m on Windows 7 x64) the revealed content is shaking.
Here's an jsfiddle example: http://jsfiddle.net/BaKTN/
So far I've found out that this can be fixed by not disabling background-repeat
(http://jsfiddle.net/BaKTN/1/). Not sure what exactly happens internally, but this makes the image stay where it belongs. Unfortunately that's only half of the problem, shaking occours again when the outer container is placed on odd coordinates, which can for example happen when using percentage based positioning (at least internally the coordinates might be odd).
Here's another jsfiddle example showing this behaviour: http://jsfiddle.net/VbgXB/
edit: Using fixed positioning seems to help, even with more outer containers that would cause odd coordinates everything looks fine. However this workaround is ofcourse only conditionally useful, since it will messs up scrolling: http://jsfiddle.net/BaKTN/5/. So I'm still looking for another trick. /edit
Any ideas what is actually causing this problem and how to circumvent it without changing the containers coordinates? Might this have something to do with this bug: http://code.google.com/p/chromium/issues/detail?id=140038 ?
ps. please note that this is ment to become part of a larger animation (multiple tiles) which needs to stay CSS2 compatible!
Upvotes: 6
Views: 1468
Reputation: 13967
This is probably due to partial pixel values for the background-position. Rounding the values seems to fix it: http://jsfiddle.net/BaKTN/2/
(function($) {
$.extend($.fx.step,{
backgroundPosition: function(fx) {
if (typeof fx.end == 'string') {
var start = $.css(fx.elem,'backgroundPosition');
start = toArray(start);
fx.start = [start[0],start[2]];
var end = toArray(fx.end);
fx.end = [end[0],end[2]];
fx.unit = [end[1],end[3]];
}
var nowPosX = [];
Relevant code
nowPosX[0] = Math.round(((fx.end[0] - fx.start[0]) * fx.pos) + fx.start[0]) + fx.unit[0];
nowPosX[1] = Math.round(((fx.end[1] - fx.start[1]) * fx.pos) + fx.start[1]) + fx.unit[1];
End Relevant code
fx.elem.style.backgroundPosition = nowPosX[0]+' '+nowPosX[1];
function toArray(strg){
strg = strg.replace(/left|top/g,'0px');
strg = strg.replace(/right|bottom/g,'100%');
strg = strg.replace(/([0-9\.]+)(\s|\)|$)/g,"$1px$2");
var res = strg.match(/(-?[0-9\.]+)(px|\%|em|pt)\s(-?[0-9\.]+)(px|\%|em|pt)/);
return [parseFloat(res[1],10),res[2],parseFloat(res[3],10),res[4]];
}
}
});
})(jQuery);
Edit — Converting your #container
position to (whole) pixels instead of percentages will fix the second case, but it won't adjust its position when the window is resized: http://jsfiddle.net/VbgXB/1/
var $con = $("#container");
$con.css({
left: Math.round($con.position().left),
top: Math.round($con.position().top)
});
Upvotes: 5