Applying A Circular Crop Mask To An Image

Profile pictures are often masked by a circle. How can we present our images in such a circle. Lets explore two options, one where we use CSS and one where we actually mask the image data.

Applying the mask using CSS

Applying a circular mask to an image using CSS is quite straightforward. We only have to set the border-radius property and we’re done.

    img {
        border-radius: 50%;

<img src="/media/cat.jpeg" alt="" />

But what if our image isn’t a square?

To prevent elliptic cats we have to make sure our image is a square.

    img {
        width: 128px;
        height: 128px;
        border-radius: 50%;

<img src="/media/cat.jpeg" alt="" />

Okay, but now our cat is squished. Let’s unsquish it using CSS object-fit.

    img {
        width: 128px;
        height: 128px;
        object-fit: cover;
        border-radius: 50%;

<img src="/media/cat.jpeg" alt="" />


Applying a Circular Mask using Canvas

To modify the actual image data we can use the <canvas> element and apply the circular mask to the image itself.

Let’s use a file input element and apply the mask to the added file.

<input type="file" accept="image/*" />

<canvas hidden></canvas>

    // get a reference to the file input
    const fileInput = document.querySelector('input');

    // get a reference to the output canvas
    const canvas = document.querySelector('canvas');

    // listen for the change event so we can capture the file
    fileInput.addEventListener('change', (e) => {
        // get a reference to the file
        const file =[0];

        // let's load the image data
        const image = new Image();
        image.onload = () => {
            // use min size so we get a square
            const size = Math.min(image.naturalWidth, image.naturalHeight);

            // let's update the canvas size
            canvas.width = size;
            canvas.height = size;

            // draw image to canvas
            const ctx = canvas.getContext('2d');
            ctx.drawImage(image, 0, 0);

            // only draw image where mask is
            ctx.globalCompositeOperation = 'destination-in';

            // draw our circle mask
            ctx.fillStyle = '#000';
                size * 0.5, // x
                size * 0.5, // y
                size * 0.5, // radius
                0, // start angle
                2 * Math.PI // end angle

            // restore to default composite operation (is draw over current image)
            ctx.globalCompositeOperation = 'source-over';

            // show canvas
            canvas.hidden = false;
        image.src = URL.createObjectURL(file);

Try it below!

I share web dev tips on Twitter, if you found this interesting and want to learn more, follow me there

Or join my newsletter

More articles More articles