While there are definitely cross browser discrepancies handling subpixels, this one caught me by surprise. Take the following:
<div id="box"></div>
<script>
var box = document.getElementById('box');
box.style.left = '10.25px';
console.log(box.style.left);
</script>
This simply sets a value for the left
CSS property then immediately retrieves it. In Chrome 22, Firefox 14, Safari 6, Opera 12, IE >= 9, iOS 5, and Android 10.25px
will be logged.
In IE < 9 10px
is logged. While not all browsers can accurately render the subpixel values, I had assumed all of them would’ve at least allowed the assignment. I was wrong. Internet Explorer will simply round the value to the nearest integer.
Why is this a problem? Take the following code.
<div id="box"></div>
<script>
var box = document.getElementById('box');
box.style.left = '0px';
setInterval(function() {
var currentLeft = box.style.left.replace('px', '');
currentLeft = parseFloat(currentLeft);
box.style.left = currentLeft + 0.25 + 'px';
}, 20);
</script>
This sets an interval that will increase the left
property of a box by 0.25
pixels every 20 milliseconds. Doing so will move the box left across the screen as seen below:
Moving a box with sub pixels Open in New Window
Great. Unfortunately in IE < 9 the box will not move. Within the interval function the value to increment is being retrieved from the element itself, which, in IE < 9 will continuously return the rounded value.
The way around this is simply to use store off the value of the property outside of the animation loop itself.
<div id="box"></div>
<script>
var left = 0;
var box = document.getElementById('box');
setInterval(function() {
box.style.left = left + 'px';
left += 0.25;
}, 20);
</script>
This has the added benefit of being more efficient since you save a property retrieval on every invocation of the loop.