3 Ways to Turn Web Images to Grayscale

By . Filed in Web Design

I’ve always been a fan of grayscale images as I think they look more artistic. Many photo editors such as Photoshop let you turn colorful images into grayscale easily. There is even the option to tune the color depth and color tones. Unfortunately, it is less straightforward to do so on the Web due to the differences in browser capabilities.


(Image Source: Kenneth Thewissen)

In this post, we are going to walk through some methods that we can use to turn images grayscale. We’ll also look into the stumbling blocks of each method and near the end, we will combine these methods to achieve a grayscale image that works across different browsers.

1. CSS Filter

Using CSS filter property is perhaps the easiest way to turn image into grayscale. Back in the old day, Internet Explorer has a proprietary CSS property called filter to apply custom effect including Grayscale.

Today, filter property is part of CSS3 specification, and supported in some browsers, like Firefox, Chrome and Safari. Previously, we have also mentioned about the Webkit filter that allows us not only to turn images grayscale but also apply sepia and blur effect.

We can add the following style rules to turn images grayscale with the filter property.

img {
	-webkit-filter: grayscale(1); /* Webkit */
	filter: gray; /* IE6-9 */
	filter: grayscale(1); /* W3C */
}

This code will take effect in IE6-9 and Webkit browsers (Chrome 18+, Safari 6.0+, and Opera 15+).

(Note: IE10 dropped support for the legacy IE filter nor it also support for the prefixed version, -ms-filter, for applying grayscale. This code does not work in Firefox either.)

2. JavaScript

The second alternative is by using JavaScript, which technically should work in all browsers that have JavaScript enabled, including IE6 and below.

Here is the code from Ajax Blender.

var imgObj = document.getElementById('js-image');
function gray(imgObj) {
    var canvas = document.createElement('canvas');
    var canvasContext = canvas.getContext('2d');
    
    var imgW = imgObj.width;
    var imgH = imgObj.height;
    canvas.width = imgW;
    canvas.height = imgH;
    
    canvasContext.drawImage(imgObj, 0, 0);
    var imgPixels = canvasContext.getImageData(0, 0, imgW, imgH);
    
    for(var y = 0; y < imgPixels.height; y++){
        for(var x = 0; x < imgPixels.width; x++){
            var i = (y * 4) * imgPixels.width + x * 4;
            var avg = (imgPixels.data[i] + imgPixels.data[i + 1] + imgPixels.data[i + 2]) / 3;
            imgPixels.data[i] = avg; 
            imgPixels.data[i + 1] = avg; 
            imgPixels.data[i + 2] = avg;
        }
    }
    canvasContext.putImageData(imgPixels, 0, 0, 0, 0, imgPixels.width, imgPixels.height);
    return canvas.toDataURL();
}
imgObj.src = gray(imgObj);

Using JavaScript method, we will be able to apply the Grayscale effect upon certain condition, such as when the image is on hover or being clicked. We can also use it along with jQuery effects to apply smooth animation when the image is transitioning from gray to full-color. The only downside that I can see from using JavaScript is that the effect will be discarded when JavaScript is disabled on the browser.

3. SVG

Another way is by using an SVG Filter.

All you need to do is create an SVG file, and put the following codes in it. Save and name the file to e.g. gray.svg.

<svg xmlns="http://www.w3.org/2000/svg">
	<filter id="grayscale">
		<feColorMatrix type="matrix" values="0.3333 0.3333 0.3333 0 0 0.3333 0.3333 0.3333 0 0 0.3333 0.3333 0.3333 0 0 0 0 0 1 0"/>
	</filter>
</svg>

Then, using the filter property, we link the SVG file followed by the ID of the filter element in our SVG file:

img {
	filter: url('img/gray.svg#grayscale');
}

You can also embed the codes directly within the CSS, like so.

img {
	filter: url('url("data:image/svg+xml;utf8,<svg%20xmlns='http://www.w3.org/2000/svg'><filter%20id='grayscale'><feColorMatrix%20type='matrix'%20values='0.3333%200.3333%200.3333%200%200%200.3333%200.3333%200.3333%200%200%200.3333%200.3333%200.3333%200%200%200%200%200%201%200'/></filter></svg>#grayscale");')
}

This will return the same result.

Conclusion

To have cross-browser support for the grayscale effect, we can put the abovementioned methods together, using the following code snippet. This code will apply the grayscale effect in Firefox 3.5+, Opera 15+, Safari, Chrome, and Internet Explorer.

img {
	-webkit-filter: grayscale(100%);
	-webkit-filter: grayscale(1);
	filter: grayscale(100%);

	filter: url('../img/gray.svg#grayscale');
	filter: gray;
}

We can utilize the above code along with the JavaScript method, and only provide CSS filter as the fallback in case JavaScript is disabled. This idea can easily be achieved with the help of Modernizr.

Modernizr will add js class in the body, if JavaScript is enabled, and it will switch the class name to no-js if it is disabled. With CSS, you can do the following.

.no-js img {
	-webkit-filter: grayscale(100%);
	-webkit-filter: grayscale(1);
	filter: grayscale(100%);

	filter: url('../img/gray.svg#grayscale');
	filter: gray;
}

That’s all, you can see the demo in action below:

Sources

Head over to the following sources for references on Grayscale and filter effect:

Author:

Thoriq is a writer for hongkiat.com. He has been dabbling in Web Design for 7 years and appreciates the giving nature of the web design community at large. He loves trying new things in CSS3 and HTML5. Apart from writing on hongkiat.com he also maintains creatiface.com.

Tags:

Advertisement