Looping content with PostCSS

A question: how often have you come across instances where you have a number of very similar images that share styles, but at the same time need to have individual styles applied? Sound familiar?

I am of course talking about instances such as list items, grid layouts, and the classic social media icons we see littered all over the Internet. We can of course simply write rules to cover each image, but as I am sure you will agree, it's not the smartest approach! Instead, we can use the power of the @each statement to iterate through each item and apply each style using string interpolation.

The @each plugin, by Alexander Madyankin, is one of two ways to incorporate a facility to loop through content; the source for this plugin is available from https://github.com/outpunk/postcss-each. The other plugin, postcss-for (available from https://github.com/antyakushev/postcss-for), takes a different approach—the difference between the two is that the former works on objects, while the latter must use a range of numbers to apply styles.

If we take the second plugin for a moment, we have to loop through a consecutive range of numbers in order to produce our result. So, something akin to this:

@for $x from 1 to 3 {
  .grid-$x { width: $(x)px; }
}

…would produce this, when compiled:

.grid-1 {
  width: 1px
}
.grid-2 {
  width: 2px
}
.grid-3 {
  width: 3px
}

Seems pretty straightforward, right? Here comes the rub, though: unlike SASS, we can't use variables to define that range by default; this plugin must be defined before any instance of postcss-nested and postcss-simple-vars plugins. In PostCSS, we iterate through all of the values inclusively (that is, one to three in our example), which is not the same as in SASS.

It's in cases like this that we must decide between using this plugin on its own, or with postcss-custom-properties and postcss-for-variables. This is why it is key to fully understand what you need to achieve, and the capabilities of plugins available, so that we can choose the most effective combination to suit our needs. The great thing about PostCSS is its flexibility, speed, and modular design; this modularity and flexibility can also be seen as its Achilles heel, as tweaking the choice and order of plugins can have a real impact on our code!

Note

We can of course change completely, and use a separate fork of the postcss-for plugin, available from https://github.com/xori/postcss-for. This caters for dollar variables.

Let's put some of this into practice. Before we get stuck in to nesting with PostCSS in the next chapter, we'll round out this one with a simple demo that uses a group of social media icons and PostCSS to set up styling automatically for us.

Iterating through @each statements

Staying with the looping theme, but on a different tack, in place of using the for statement, we can achieve similar effects with @each, but only if the target is an element on the page.

I am of course talking about elements such as buttons or menu items; these elements will share the same styling, but require unique IDs to allow us to interact with them. It goes without saying that we could simply create a shared base class and add multiple classes for each element…

But we can do better than that: most preprocessors have in-built functionality that allows us to iterate through elements and apply CSS styling to each element. Thankfully, PostCSS is no different; we can achieve the same result using the postcss-each plugin, available from https://github.com/outpunk/postcss-each. It's a cinch to install, and we can use it to add elements such as social media icons to the foot of a page, and style them. I feel a demo coming on, so let's dive in and take a look:

  1. We'll start with installing the plugin, so go ahead and fire up a NodeJS command prompt, and change the working directory to our project area.
  2. At the prompt, enter this command to install the postcss-each plugin, then press Enter:
    npm install --save-dev postcss-each
    
  3. If all is well, we should see the customary confirmation that the plugin is installed:

With the plugin now in place, let's move on and update our gulp file:

  1. We need to make three changes to our gulp file, so go ahead and open a copy from the project area in your usual text editor.
  2. First, go ahead and remove lines 9 to 11; they contain the variable declarations for the postcss-css-variables and postcss-mixins plugins.
  3. On or around what is now line 8, we should see the variable declaration for postcss-calc. Immediately, below, add the following line:
    var eachloop = require('postcss-each');
  4. In the main autoprefixer task, we need to alter the postcss call; remove this from line 13:
    cssvariables(/* options */), cssmixins(/* options */), calc(/*options*/),

    We should be left with this (changes have been highlighted):

    .pipe(postcss([ autoprefixer, cssnano(), foreach(/*options*/) ]))

At this point, we can save the file. It is now ready for us to process the CSS required for our next demo. For this next exercise, we will need to avail ourselves of some suitable social media icons. I've used the ones by Nathan Brown, available at http://wegraphics.net/downloads/free-stained-and-faded-social-media-icons/. We'll use the Twitter, LinkedIn, and YouTube images.

Let's make a start:

  1. We'll start with a look at the SASS version of this demo. It's a simple example, but illustrates perfectly how we can use the @each function to iterate through each image and apply the appropriate style:
    $social: twitter, linkedin, youtube;
    
    .social-icon {
      // shared information here
      background: 50% no-repeat;
      background-size: 100%;
      float: left;
      height: 50px;
      width: 50px;
       
      // unique information loops here
      @each $network in $social {
        &.#{$network} {
          background-image: url("../img/#{$network}.png");
        }
      }
    }
  2. To compile the code, go ahead and copy the Tutorial4 folder to our project area.
  3. Replace the existing gulpfile.js with a copy from the Tutorial1A folder—this contains the appropriate commands to compile the code—we need to use the original version built to compile SASS code, not PostCSS, hence the change.
  4. Take a copy of style.scss from the src folder of the Tutorial4 folder, then drop it into the src folder of our project area.
  5. Next, fire up a NodeJS command prompt window, then change the working folder to our project area.
  6. At the prompt, enter this command, then press Enter:
    gulp
    

    Keep the command prompt window open for now, we will use it again shortly.

  7. Once the code has compiled, copy the contents of the dest folder back to the css folder in the Tutorial4 folder.

If all is well, we should have three icons showing, when previewing the results in a browser. Nothing outrageous here: we have the base rule that applies to all of the icons, which is followed by the individual classes required to handle each icon itself:

.social-icon {
  background: 50% no-repeat;
  background-size: 100%;
  float: left;
  height: 50px;
  width: 50px;
}

.social-icon.twitter {
  background-image: url("../img/twitter.png");
}

.social-icon.linkedin {
  background-image: url("../img/linkedin.png");
}

.social-icon.youtube {
  background-image: url("../img/youtube.png");
}

So, how would this look in PostCSS? Well, surprising as it may be, there isn't a great deal of change needed.

Switching to using PostCSS

We only need to change it in two places within our CSS file. I've also separated the nested code, to make it easier to view:

.social-icon {
  // shared information here
  background: 50% no-repeat;
  background-size: 100%;
  float: left;
  height: 50px;
  width: 50px;
}

The changes we need to make are highlighted in this block of code:

@each $media in twitter, linkedin, youtube {
  . $(img) {
    background: url('../img/$(media).png');
  }
}

Our gulp file also needs to change. Let's work through the steps involved to make the switch to PostCSS:

  1. We first need to replace the gulp file—go ahead and delete the copy at the root of the project area, then replace it with a copy from the Tutorial4 folder in the code download.
  2. From the code download that accompanies this book, extract a copy of stylepre compile.css, and rename it as style.css. Drop it in the src folder of our project area.
  3. Revert back to the command prompt, then enter gulp at the prompt and press Enter.
  4. If all is well, we should see the compiled style sheets appear in the dest folder, along with the source maps.
  5. Copy the contents of the dest folder in project area to the css folder within our local copy of the Tutorial4 folder.
  6. Try previewing the results in a browser; if all is working as expected, we should see these icons appear:

Granted, it is a simple exercise, but then I've always been a fan of keeping things simple! Anyone can write CSS styles, but for me the "step up" is knowing that quantity does not always beat quality, and that there is something to be said for following the KISS principle, Keep It Simple… Yes, you get the idea!

But, just to show how flexible this plugin is, try this as an exercise:

  • Browse to http://dataurl.net/, then upload each of the icons in turn, and use the site to generate data-URI equivalent code for each image.
  • In the CSS, remove the existing background-image links, and replace them with the code from the dataurl.net site.
  • Go ahead and compile the code using the same principles we've used throughout this chapter. Looks identical, doesn't it? We've removed the need to pull in separate resources, as we're using a pure CSS solution...

But, there is a catch: when the file has been compiled, check the file size. It should tell you that it is significantly larger than the one which doesn't contain data-URI equivalent code. This is to be expected: it's the trade-off between sizes versus the number of resources we call. It only shows how critical the order of our PostCSS plugins would be, to get the desired results!