Look at this lil fella:
If you've ever rendered a jpeg on the internet you've probably seen something like this:
It's blurry because the browser is interpolating the missing pixels, smearing the few pixels over the screen. This works fine for large images or small differences in size, but what if I actually want to see those chunky pixels.
What I actually want it to look like is this:
Browsers are making this possible with a new CSS rule: image-rendering: pixelated;
The browser support for this is pretty good, but not universal. You can check it out on Can I Use.
img {
image-rendering: pixelated;
}
// Wow that was easy.
What about those poor browsers that don't support it yet? We can't just let them have gross stretched out blurry pixels. They want crisp blocks too. Nay, they need them.
How about some JavaScript? Sure. Turns out browsers have added a neat little API to detect whether a browser supports some CSS.
let supportsPixelated =
CSS &&
CSS.supports &&
CSS.supports("image-rendering", "pixelated")
What we're saying here is if the CSS
object exists and if the CSS
object
has a supports
function on it, we can call it with the CSS property and value
we want to use. If any of this returns false
it's safe to say that the
browser does not support it. If it's true then it does. So now we know if the browser
supports image-rendering: pixelated
we can leave it alone if it does and do something
about it if it doesn't.
Turns out the next part is also pretty easy.
let img = document.querySelector("img")
let canvas = document.createElement("CANVAS")
canvas.width = img.width
canvas.height = img.height
img.parentNode.insertBefore(canvas, img.nextSibling)
let ctx = canvas.getContext("2d")
ctx.imageSmoothingEnabled = false
ctx.drawImage(img, 0, 0, img.width, img.height)
img.parentElement.removeChild(img)
Okay so that was like nine lines of code in a row so let's go through it one at a time and figure out what we're doing together.
let img = document.querySelector("img")
let canvas = document.createElement("CANVAS")
canvas
.
canvas.width = img.width
canvas.height = img.height
img.parentNode.insertBefore(canvas, img.nextSibling)
let ctx = canvas.getContext("2d")
ctx.imageSmoothingEnabled = false
ctx.drawImage(img, 0, 0, img.width, img.height)
img.parentElement.removeChild(img)
And that's it. We replace the <img /> with a <canvas /> containing the same image.
And here's how it looks:
<img
src="/img/chonky-pixels/small.jpg"
class="demo-canvas"
/>
<style>
.demo-canvas {
image-rendering: pixelated;
width: 100%;
}
</style>
<script>
window.addEventListener("load", function() {
let img = document.querySelector(".demo-canvas")
let canvas = document.createElement("CANVAS")
canvas.width = img.width
canvas.height = img.height
img.parentNode.insertBefore(canvas, img.nextSibling)
let ctx = canvas.getContext("2d")
ctx.imageSmoothingEnabled = false
ctx.drawImage(img, 0, 0, img.width, img.height)
img.parentElement.removeChild(img)
})
</script>
This isn't totally finished. We deleted the image tag without carrying over any
of the accessibilty like the alt
attribute. That's okay if it's purely decorative,
but otherwise you gotta do it. Promise?
Cool! Have a happy Thursday! — @dnrvs