Back

TechnologySep 24, 2014

Modern Web Development Best Practices Powered by Grunt.js Part 11: Data URI & Image Optimization

Fernando Berrios

In the last part of this series we talked about image spriting, but there’s also an alternate approach: using the data URI scheme. It will allow you to drop that extra image sprite HTTP request but at the expense of increasing the overall size of the generated CSS. This approach uses the data URI scheme that is supported in newer browsers (check this compatibility chart) to convert an image into a string of text the browser can represent as an image. Compass includes a few helpers we’ll use to get our sample project to utilize this technique.

tutorial:

git checkout inline-image

Data URI Inline Images

Only a few changes are required to implement this feature. First, we create a simple mixin that will set the background image, width, and height to the elements that have been applied.

@mixin bg-inline-image($image) { background-image: inline-image($image); height: image-height($image); width: image-width($image); }

This mixin takes only one argument, which is the relative path to the image. To use it, we can do this:

&.logo-1 { @include bg-inline-image("icon/compass.png"); }

&.logo-2 { @include bg-inline-image("icon/map.png"); }

I’ve converted the elements we previously had using sprites to now be inline images. That’s it! Once “grunt compass” is run and the page is refreshed, it will look exactly the same. But the generated CSS will look a bit different:

Notice those highlighted strings? Those are the encoded images, which have become really long strings embedded in the CSS. Also notice that they go past the margins of my text editor. They go on for quite a bit (how long depends on the image). Keep in mind that most modern web servers will compress the output before it is sent to the client, and text always compresses better than images. But you might not want to have all your images as inline images. This technique works well when you have a small to medium set of images you need to use. It also works without conflicting with CSS sprites, so you can choose both depending on your needs.

Image Optimization

For whichever approach you take, there is an additional step to optimize the size of images. Programs like PNGGauntlet, ImageOptim, as well as the “Save For Web” function of Photoshop allow you to shave off a few kilobytes from your image files by applying compression algorithms and removing unnecessary metadata and color profiles. While handy, these applications must be run manually as they are Graphical User Interface (GUI) applications. Fortunately, under the hood all these apps delegate their image optimization tasks to Command-Line Interface (CLI) programs, which means we can once again make use of Grunt.js to automate things.

tutorial:

git checkout imagemin npm install

To implement this we will use the “grunt-contrib-imagemin” plugin. This employs a few CLI tools (OptiPNGpngquantjpegtran, and gifsicle) to optimize different types of images. For our case, we will optimize the sprite image we created a few steps back. To do this we add this configuration to the “grunt.initConfig” section:

imagemin: { png: { options: { optimizationLevel: 7 }, files: [ { expand: true, cwd: imgFolder, src: ['icon-*.png'], dest: imgFolder } ] } }

Now when we run “grunt imagemin,” the task works its magic:

As you can see in the screenshot above, our sprite image was reduced by 73 kB (from ~104 kB to ~31 kB), and there is no discernible change in the image quality. Nice!

Keep watching this blog for the last part of this series, in which we’ll discuss using feature detection and dead code removal techniques.  In the meantime, follow @CrederaMSFT on Twitter and Credera on LinkedIn for more great best practices.

To view the rest of the Modern Web Development Best Practices Powered by Grunt.js series click here.