pixel-perfect.js

The images below should be displayed "pixel-perfect" (at least on Chrome/Edge/Firefox). details below

Try zooming in and out with



    
pixel perfect
browser image-rendering: pixelated
browser image-rendering: smooth (default)

WAT?:

Sometimes you want to display pixel art and you want it displayed "pixel-perfect" meaning you don't want any blurring of the pixels and you want each pixel in the original image to be some multiple of pixels on the user's device. In other words, say you have this 16x16 image.

You might think using image-rendering: pixelated or image-rendering: crisp-edges would work. Unfortunately it won't. The reason is: fractional devicePixelRatios!

current devicePixelRatio:

Many devices have fractional devicePixelRatios. The devicePixelRatio is the ratio of the number of actual pixels to each CSS pixel (CSS pixels are what the browser uses). So, that 16x16 pixel image, by default, in every browser, will be displayed at 16 * devicePixelRatio. If the devicePixelRatio is 1.5 then it's going to draw the image 24x24 pixels large on the display. By default, most browsers will use bilinear filtering. Below is the same image as above with the browser's default.

Setting image-rendering: pixelated or image-rendering: crisp-edges will change the filtering to "nearest-neighbor" (*) but it doesn't solve the issue that you can't scale a 16x16 pixel image into a 24x24 pixel space without making some pixels larger than others. In other words, it will not be "pixel-perfect".

This script attempts to solve it. You give the image a css size and pixel-perfect will adjust the image's CSS width and height so that given the user's current devicePixelRatio the image will be displayed such that each pixel in the original image is scaled the same size as all the other pixels, or "pixel perfect".

Issues:

In order to be able to display images pixel perfect you must let the image change size on the page relative to other things. In the examples at the top of the page, try zooming in and out. Notice the 2 "pixel perfect" images do not scale smoothly. Instead they "jump" to the closest size that fits, scaling the all the pixels by the same integer size. To put it another way, a 100x100 image can only appear on the page at 100x100, 200x200, 300x300, 400x400, etc... It can't be 50x50 nor can it be 150x150. Those sizes would not be "pixel-perfect".

Compare the 3 images above as you change the zoom level. The one on the left, being pixel perfect, may change its size relative to the others to maintain pixel perfection.

Canvas

It works for <canvas> tags as well but with the same issue. The canvas must be allowed to resize.

How to Use:

See the ReadMe.

Fork me on GitHub