2

Both style.top and translateY() seem to round to full pixel values. Is there any way to get an image to rest on a subpixel?

As an example, here I am moving a div with an image in it down 0.1 pixels every 100ms, and as you can see, it just jumps a full pixel every second. https://jsfiddle.net/je391bfr/

var i= setInterval(function() {this.myTimer(); },100);
var y=0;
var div=document.getElementById('mytest');
function myTimer(){

  this.y+=.1;
  console.log(this.y); 
  //var tr="translateY("+this.y+"px)";
  var tr="translate(0,"+this.y+"px)";
  this.div.style.webkitTransform=tr;
  this.div.style.mozTransform=tr;
  this.div.style.msTransform=tr;
  this.div.style.oTransform=tr;
  this.div.style.transform=tr;
}

Note: I want something that can STOP on a subpixel if I want, not just be on a subpixel during animation.

Jacob
  • 77,566
  • 24
  • 149
  • 228
  • I don't believe this is possible with HTML/CSS, but you could probably achieve it by embedding the image in a `canvas` or `svg` element. – nrabinowitz Jul 31 '15 at 18:08

1 Answers1

1

This can be done using CSS3 transform property where you get to translate the image using translate method where you provide it the sub-pixel you need for the y-axis coordinate (in a similar manner to your example).

The translation is never smooth without the use of a small rotate that helps to better utilize the rendering engine rotate(.0001deg) and shall ease the sub-pixel rendering.

Following is a snippet....

To stop the animation, simply use clearInerval(i), it will stop at whatever sub-pixel it reaches.

var imgPos = 0.0;
var offset = .2;

function myTimer(){
    imgPos += offset
    $("#img").css('transform', 'translate(0,' + imgPos + 'px) rotate(.0001deg)');
}

var i= setInterval(function() {myTimer(); },100);
  
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<body style="background-color:#ffffff; padding:0px; margin:0px;">


<div id="mytest" style="overflow: visible; display: inline-block; position: absolute; width: 152px; height: 56px; left: 0px; top: 0px; padding: 0px; margin: 0px; cursor: pointer; opacity: 1; "><img id="img" style="width: 100%; height: 100%; display: inline-block; position: absolute;" src="https://d138hkes00e90m.cloudfront.net/banner_images/Lazarus18_Large_Banner.jpg"></div>

</body>
KAD
  • 10,972
  • 4
  • 31
  • 73
  • Thanks, but this only seems to work in Chrome, not in firefox/ie :/ – user3134006 Aug 01 '15 at 21:38
  • Try using the firefox vendor prefix `-moz-` and IE vendor prefix `-ms-` with transform. – KAD Aug 02 '15 at 05:42
  • Or you can use jQuery 1.8.0+, it automatically adds vendor prefixes. – KAD Aug 02 '15 at 05:50
  • Also here is a [fiddle](http://jsfiddle.net/molokoloco/f6z3d/) to add prefixes manually to jquery css. – KAD Aug 02 '15 at 05:54
  • tried using slight rotation on the translation and vendor prefixes but still only works in chrome. The rotation seems to make it look really distorted also, so it ends up jumping to pixel values on the x/y AND looking distorted. I found translate3d(0,0,0) seems to work better then rotation to make subpixels work in chrome. For other browsers it seems nrabinowitz is right in that I must use the canvas to get subpixels. – user3134006 Aug 03 '15 at 15:53
  • I should clarify, translate3d(0,0,0) has a different smoothing effect then rotation. Rotation is blurry, translate3d is pixely, but both cause image to rest on a subpixel in chrome. – user3134006 Aug 03 '15 at 16:06
  • Here's another [jsfiddle demonstrating the rotate method](https://jsfiddle.net/ryanwheale/xkxwN/). – jfroom Jun 15 '16 at 21:21