Working with Images in Stylesheets with PostCSS

Share this:

The following is a guest post by Aleks Hudochenkov. Aleks does a great job here of showcasing what PostCSS is good at and the role it has grown into in the front end stack. That is: doing little useful jobs within CSS. You're about to see a variety of PostCSS plugins at work that are all related to working with images. By the end, I bet you'll be able to imagine how PostCSS can be useful for other niches within working with CSS.

We all work with images in our CSS. Routine stuff. We may not even realize it, but there many be a lot of manual work involved this with that could be made a lot easier. I'm going to be showing you a variety of PostCSS plugins that are specfically designed to help with working with images in CSS.

Every plugin described in this article works with every syntax PostCSS can parse — CSS, SCSS, Less and syntaxes created by PostCSS plugins. I will not describe how to use PostCSS itself, because there is already an excellent article by Drew Minns.

Let’s start with plugins which cover most of the use cases when dealing with images in CSS.

Image Helpers

The postcss-assets plugin is an almost essential plugin for dealing with images. It has lots of functionality.

Inlining images

Sometimes making images into data URL's inside our stylesheet is useful. One less HTTP request!

Inline and modify SVGs

Almost every graphic I deal with lately is SVG. It's a great format that handles any pixel density display. Even better, the syntax for it is text, meaning we can edit them without heavy tools like graphic editing programs.

Say we have a star icon that we use in ten different places with different colors around our site. There are many ways we can do this. We could use an inline SVG system with <symbol></symbol> and <use> and all that. Or, we can use background property in CSS!

There are two ways to use an image in CSS. 1) a url(/path/to/image.jpg) value with a file path or 2) a url(data:...) value with a data URL. The later is sometimes known as "inlining" images, which accomplishes one of the major advantages of image sprites: combining HTTP requests. With postcss-inline-svg, we can do this (making our CSS file our sprite), and still adjust the colors independently:

Will the output CSS file be enormous, you ask? Yes and no. The output CSS will be bigger because of code duplication, but it doesn’t matter because of Gzip! To demonstrate, I’ve made a test. I’ve created a CSS file with 100 different selectors and add an inline icon in every ruleset with a random color for the fill. Like so:

Then I created a duplicate of this file, and removed all those inline backgrounds. Here are the file size results:

Original size

Gzipped

With 100 images

48500 bytes

2560 bytes

With 1 image

3158 bytes

1817 bytes

Difference: 2560 – 1817 = 743 bytes

Not a big difference!

The only con of this approach: there is no way to animate changes of image. For example, if color should change on hover with a transition, there is no convenient way to do this because transition will not be applied to background-image.

These plugins compliment each other

Real world example: we need a button that is an icon. The image inside the button needs a specific image size and also needs to change color on hover. There is only one source SVG file.

If the image changes, you don't need to do anything! postcss-assets will update sizes. Need to change a color? They are right here in CSS. You can even use variables if you are using another plugin or preprocessor that offers those.

Sprites

There are still some reasons you might want to use the kind of image sprite where all the images are combined together into one larger image. For one, it is known that mobile phones decode inline images slightly slower than regular images.

There are lots of tools for creating image sprites. For example: grunt-spritesmith. These are powerful, aren't particularly easy to set up or convenient. In grunt-spritesmith, for example, you need to understand how its templates engine works.

It finds every image in CSS (filtering is possible), creates a sprite, and outputs the correct background-position to get there.

Handling sprites for high-density screens

Despite postcss-sprites support for retina images, it doesn't quite give you production ready code. For example, it doesn't give you media queries to target high-density screens to actually use those images. This problem can be solved with another PostCSS plugin. This is a beauty of PostCSS ecosystem — there are many plugins which do only one job, and you can combine them for solving more complicated problems.

There is a postcss-at2x plugin which adds media queries targeting high-density screens. Let’s combine these plugins to generate a sprite for both normal and high-density screens.

Create images on the fly

Sometimes we need really simple images (like geometric shapes), but still find ourselves opening a graphic editor, creating the image, exporting it, putting it in the right place, optimizing it, and using it in CSS. What if we can could create simple images right in a CSS? I bet you can guess: we can!

postcss-write-svg allows you to create simple SVG images right in CSS. Just describe SVG elements and it will be inlined as background-image.

There are other plugins to make circles and triangles with only CSS properties. Triangles. You can do triangles yourself in CSS, but it's not exactly straightforward and gets harder when you want to do different types of triangles. postcss-triangle allows to you to easily create isosceles, right isosceles and equilateral triangles.

Cachebusting

Say you need to update an image linked to in a stylesheet. We might run into a problem if we're using far out expires headers, and the user's browser is hanging onto that image in cache. The solution is to force that user's browser to download the new version (cachebust). There are two ways to do this: change a filename or change the URL. Changing the filename is a lot to ask, but changing URL is easy thanks to URL parameters.

Utilities

PostCSS plugins can help with optimizing stylesheets. For example postcss-svgo can optimize inlined SVG with SVGO, the best SVG optimization tool.

If you still need to support browsers which doesn’t support SVG, but you like to use SVG, postcss-svg-fallback can help you. This plugin generates PNG fallbacks for SVG in you CSS (both inlined and linked via url()) and adds additional rules in CSS for old browsers.

Inlining images might bloat output CSS, but there is a solution: postcss-data-packer can extract embedded data URLs into a separate file. Now you can load this file asynchronously to decrease page load time.

Conclusion

Before PostCSS, we did a lot of tedious manual work: copy and pasting things, duplicating things, or manual calculations. Now we can use some PostCSS plugins, to make our computers do things for us. It speeds up our work and makes us happier people.

Hey, Chris! Great examples. Thanks.
About animation approach. You can always use opacity transition between to layers with inlined images. It’s very performant and as you said do not increase size too much with gzip.

Great post. Small quibble though. CSS which has 100 same images inline may have approximately same size on wire, but it expands to its full size on client and is parsed as such. As client has no way of knowing that those images are really mostly the same, it can’t optimize parsing or memory use. You may still end up with noticeable negative effect.

I don’t think this invalidates your approach, just that we have to be mindful about what we do (as we ought to be anyway).

This comment thread is closed. If you have important information to share, please contact us.

Related

How do you stay up to date in this fast⁠-⁠moving industry?

A good start is to sign up for our weekly hand-written newsletter. We bring you the best articles and ideas from around the web, and what we think about them.

👋

CSS-Tricks* is created, written by, and maintained by Chris Coyier and a team of swell people. It is built on WordPress and powered up by Jetpack. It is made possible through sponsorships from products and services we like.