Table of Contents for
Mastering PostCSS for Web Design

Version ebook / Retour

Cover image for bash Cookbook, 2nd Edition Mastering PostCSS for Web Design by Alex Libby Published by Packt Publishing, 2016
  1. Cover
  2. Table of Contents
  3. Mastering PostCSS for Web Design
  4. Mastering PostCSS for Web Design
  5. Credits
  6. About the Author
  7. About the Reviewer
  8. www.PacktPub.com
  9. Preface
  10. What you need for this book
  11. Who this book is for
  12. Conventions
  13. Reader feedback
  14. Customer support
  15. 1. Introducing PostCSS
  16. Introducing PostCSS
  17. Setting up a development environment
  18. Creating a simple example using PostCSS
  19. Linting code using plugins
  20. Exploring how PostCSS works
  21. Summary
  22. 2. Creating Variables and Mixins
  23. Creating a hover effect example
  24. Transitioning to using PostCSS
  25. Adding variable support to PostCSS
  26. Updating our hover effect demo
  27. Setting the order of plugins
  28. Creating mixins with PostCSS
  29. Looping content with PostCSS
  30. Summary
  31. 3. Nesting Rules
  32. Navigating through pages
  33. Transitioning to using PostCSS plugins
  34. Exploring the pitfalls of nesting
  35. Making the switch to BEM
  36. Exploring our changes in more detail
  37. Summary
  38. 4. Building Media Queries
  39. Exploring custom media queries in PostCSS
  40. Making images responsive
  41. Adding responsive text support
  42. Optimizing media queries
  43. Retrofitting support for older browsers
  44. Moving away from responsive design
  45. Taking things further with CSS4
  46. Summary
  47. 5. Managing Colors, Images, and Fonts
  48. Managing fonts with PostCSS
  49. Creating image sprites
  50. Working with SVG in PostCSS
  51. Adding support for WebP images
  52. Manipulating colors and color palettes
  53. Creating color functions with PostCSS
  54. Summary
  55. 6. Creating Grids
  56. Creating an example with Bourbon Neat
  57. Exploring the grid plugins in PostCSS
  58. Transitioning to using PostCSS-Neat
  59. Creating a site using Neat and PostCSS
  60. Adding responsive capabilities
  61. Summary
  62. 7. Animating Elements
  63. Moving away from jQuery
  64. Making use of pre-built libraries
  65. Switching to using SASS
  66. Making the switch to PostCSS
  67. Exploring plugin options within PostCSS
  68. Updating code to use PostCSS
  69. Creating a demo in PostCSS
  70. Optimizing our animations
  71. Using our own animation plugin
  72. Summary
  73. 8. Creating PostCSS Plugins
  74. Dissecting the architecture of a standard plugin
  75. Creating an transition plugin
  76. Building a custom font plugin
  77. Simplifying the development process
  78. Guidelines for plugin building
  79. Making the plugin available for use
  80. Summary
  81. 9. Working with Shortcuts, Fallbacks, and Packs
  82. Exploring plugin packs for PostCSS
  83. Adding shortcuts with Rucksack
  84. Linting and optimizing your code
  85. Providing fallback support
  86. Summary
  87. 10. Building a Custom Processor
  88. Exploring our processor
  89. Dissecting issues with our processor
  90. Optimizing the output
  91. Adding reload capabilities
  92. Extending our processor further
  93. Testing the final pre-processor
  94. Getting started with some hints and tips
  95. Introducing the CSStyle library
  96. Summary
  97. 11. Manipulating Custom Syntaxes
  98. Preparing our environment
  99. Implementing custom syntax plugins
  100. Parsing CSS
  101. Formatting the output with the API
  102. Highlighting our syntax code
  103. Summary
  104. 12. Mixing Preprocessors
  105. Exploring the conversion process
  106. Introducing the Pleeease library
  107. Compiling with other preprocessors
  108. Using the PreCSS library
  109. Converting a WordPress installation
  110. Setting up our environment
  111. Considering the conversion process
  112. Making changes to our code
  113. Compiling and testing the changes
  114. Summary
  115. 13. Troubleshooting PostCSS Issues
  116. Exploring some common issues
  117. Getting help from others
  118. Summary
  119. 14. Preparing for the Future
  120. Converting CSS4 styles for use
  121. Supporting future syntax with cssnext
  122. Creating plugins to provide extra CSS4 support
  123. Summary
  124. Index

Creating an transition plugin

The idea for this plugin is not new; it's loosely based on the postcss-transform-shortcut plugin by Jonathan Neal, available from https://github.com/jonathantneal/postcss-transform-shortcut. The concept is not necessarily a shorter means to create transition statements, but it makes it easier by allowing authors to specify values independently. These are then automatically inserted into the correct order within the transition declaration.

Note

The source code for this plugin is also available on GitHub, at https://github.com/alexlibby/postcss-transition-shortcut; the NPM package is also available at https://www.npmjs.com/package/postcss-transition-shortcut.

Let's dive in and take a look at how it is put together, in more detail:

  1. We'll start by installing Git—this is required for installing the plugin boilerplate. To do this, browse to https://git-scm.com/book/en/v2/Getting-Started-Installing-Git, and follow the instructions for your platform.
  2. Open a Node.js command prompt, then change the working folder to our project directory.
  3. In the prompt, enter this command then press Enter:
    git clone https://github.com/postcss/postcss-plugin-boilerplate.git
    
  4. Git will clone the postcss-plugin-boilerplate repository to our project area, as shown in this screenshot:
    Creating an transition plugin
  5. The plugin boilerplate includes a script to automatically generate the skeleton for our plugin—go ahead and run this command in the prompt:
    node ./postcss-plugin-boilerplate/start
    
  6. It will show a series of prompts for various bits of information. Go ahead and fill in appropriate responses, similar to that shown in this screenshot. Note that it is not obligatory to have a GitHub account, as the information is simply added to the package.json file; if you spend any time developing plugins in the future, then it is recommended that you go ahead and create one:
    Creating an transition plugin
  7. Once the plugin folder has been created, we can remove the postcss-plugin-boilerplate folder from the project root folder, as this is no longer needed.
  8. If all is well, we should see something akin to this screenshot, when browsing the contents of our plugin folder:
    Creating an transition plugin
  9. At this point, we can now add the code for our plugin into index.js—to do this, open up a copy of the file from within the postcss-transition-shortcut plugin from within our project area, and alter the code as shown:
    var postcss = require('postcss');
    
    module.exports = postcss.plugin('postcss-transition-shortcut', function (opts) {
      opts = opts || {};
    
      var defaults = {
        property: 'all',
        duration: '1s',
        timing: 'ease-in-out',
        delay: '1s'
      };
    
      return function (css, result) {
        css.walkRules(function (rule) {
          var transitionRule;
          var transitionValues = [];
          var index = -1, node;
          var attributes = /^ (property|duration|timing|delay)$/;
    
          while (node = rule.nodes[++index]) {
             if (attributes.test(node.prop)) {
              transitionRule = transitionRule || node.cloneBefore({ prop: 'transition' });
              var transValues = postcss.list.space(node.value);
              transitionValues.push(transValues.join(','));
              node.remove();
              --index;
            }
          }
          transitionRule.value =
            transitionValues.join(' '); 
          });
      };
    });

At this stage we will have a working plugin—the proof, though (to quote an old English saying), is in the pudding: does the plugin work as we expect? Well, there's no better way to find out than by trying it out, so let's set up a quick demo to confirm it works as expected. Before we do so, though, there is one important point I need to make, which concerns the generation of PostCSS plugins.

Creating a test for our plugin

The sharp-eyed amongst you will notice though that if we don't specify one of the four values for our transition plugin, then the code at present won't use the default; hopefully an update will come in a future version of the plugin.

This aside, the process for testing our plugin uses the AVA test runner, available from https://github.com/sindresorhus/ava. The framework for the test is already created within the plugin boilerplate, which leaves us to add the test code to test.js file. Let's take a peek at what's required:

  1. We'll start by installing the AVA test runner—for this, fire up a Node.js command prompt, and change the working folder to the root of our plugin folder.
  2. In the prompt, enter these commands, pressing Enter after each—the first installs AVA, with the second adding it to our package.json file:
    npm install --global ava
    ava --init
    
  3. Open a new file in your text editor of choice—go ahead and add the following highlighted lines to test.js, within the plugin folder we created in the previous exercise:
          t.same(result.warnings().length, 0);
        }); 
    } 
    
    
    test('transitionShtct', t => { 
      return run( t, 'div { property: all; duration: 1s; timing: ease-in-out; delay: 1s; }', 'div { transition: all 1s ease-in-out 1s; }', { }); 
    });
    
  4. Next, fire up a Node.js command prompt, then change the working directory to our plugin project folder.
  5. At the prompt, enter npm test and press Enter.
  6. AVA will perform the test, which is then linted using ESLint. If all is well, we should see the results shown in this screenshot—assuming nothing was amiss with the test:
    Creating a test for our plugin

All good so far, right—at this point, we're OK to create a simple demo to prove plugin works…or are we? Well, the test shows a pass, so the code should be OK. But further down there are a ton of errors displayed, similar to this screenshot—what gives?

Creating a test for our plugin

The test has passed, yet the tests would seem to indicate otherwise; a look further down reveals yet more errors:

Creating a test for our plugin

This raises some important points about testing, so let's cover these before continuing with our demo.

Correcting the errors

The main error, or Exported linebreaks to be 'LF'…, is a simple one to fix—it's being caused by Sublime Text being set to use Windows as the default line endings setting. Assuming we're using Sublime Text, let's go ahead and deal with that error:

  1. Open up Sublime Text, then open index.js from our plugin folder.
  2. Click on View | Line Endings.
  3. Change the selected option to Unix, and save the file.
  4. Repeat steps 1 to 3 for test.js—once done, close both files.

If we re-run the test, we should see a significant drop in listed errors—there will be some left for us to fix in index.js and test.js, similar to this screenshot:

Correcting the errors

Most of the errors are self-explanatory—the two that are less obvious are Expected indentation of X spaces… and Line X exceeds the maximum line length…. We can fix the first by replacing all instances of tabs with four individual spaces per tab. The second error is simple to fix—simply split the line of code into two lines.

We need to work through all of the remaining errors, as far as possible—these won't entirely be the same for your version of the plugin, but some will be similar.

Tip

If you come across any errors where you want to understand the reason behind the error, take a look at https://jslinterrors.com/—it's a great source for defining what an error means!

Assuming we've cleared most of the errors, we should be left with just one:

Correcting the errors

Is this an error we should fix, and therefore can clear from the report? The simple answer is that it depends—it highlights an important point about using linting for code, so let's take a moment to cover this in more detail.

Clearing the final error

The last error shown in the report presents some challenges—the code is valid, yet ESLint flags the error. The reason for this is that it has found an assignment expression within a while statement initializer; it is treated as a possible mistake in the code and may have unintended effects on the code.

In some respects, it can be treated as a warning, and not necessarily as an error. Prior to July 2013 we could have configured our test to ignore this, but changes made to ESLint since that date mean that this error cannot be cleared without reworking the code.

Note

If you would like to understand more about the causes of this error, then please refer to http://jslinterrors.com/unexpected-assignment-expression/.

In our instance, the code is valid and will not cause any errors—it leaves us with several options as to what we can do going forward:

  • We can simply ignore the error and carry on—it's not great that the test fails, but in this case it won't cause any harm to our code
  • We can switch off the test for it, so that while this condition is not tested, the test will at least show a 100% pass
  • We can look to alter the code to design out the error/warning—this is the ideal solution, but it may be a longer term route, depending on the nature of the changes we need to make

For now, we're going to switch off the test for this error—we can do this by editing the .eslintrc file from within our plugin, and set the value in square brackets to 0:

Clearing the final error

This will work in the short term, but with a view to revisiting the code to design out the ambiguity at some point in the future.

Performing a test using the plugin

With our plugin in place, let's test it out—for this, we need a couple of files from the code download that accompanies this book; the files are available in the T43 – building a transition shortcut plugin folder:

  1. Go ahead and extract copies of gulpfile.js and package.json, then save them to the root of our project area.
  2. In a new file, add the following CSS styles, saving it as style.css in the src folder in our project area:
    div {
      property: all;
      duration: 1s;
      timing: ease-in-out;
      delay: 1s;
    }
  3. Fire up a Node.js command prompt, then change the working directory to our project area.
  4. At the prompt, enter gulp then press Enter—PostCSS will go away and compile the source style sheet. If all is well, we should see the compiled results of our style sheet in the dest folder of our project area:
    Performing a test using the plugin

At this stage, we've run the test for our plugin—we go one step further, and add our plugin to a test runner service such as Travis CI (at https://travis-ci.org). Although this is a mandatory part of the process for creating any PostCSS plugin, there is a fairly steep learning curve, and anyone working on Windows may run into difficulties! If you are a Windows user, you will have to make test.js executable via the command line—this requires prior knowledge of using Git, which is beyond the scope of this book.

For now, we'll skip past the Travis CI part of the process—the plugin is sufficiently straightforward that the local testing with test.js will suffice. Let's change tack—our plugin contains a number of useful concepts in PostCSS, so let's explore how it is put together in more detail.

Dissecting our plugin in detail

The inspiration for this plugin is twofold—at the time of writing, PostCSS doesn't have a great number of animation-based plugins, and it borrows the same concept used in the postcss-transform-shortcut plugin.

We start with the ubiquitous call to initialize PostCSS as a dependency for our plugin:

var postcss = require('postcss');

Next up, we initialize postcss.plugin, to expose functionality within our plugin to the ecosystem:

module.exports = postcss.plugin('postcss-transition-shortcut', function (options) {

At present, our plugin doesn't contain any options, so it will be set as blank; if we had had some options set, then these will be stored in the options array:

options = options || {};

A key part of our plugin is to set some default options—we need to have some default values set, if we don't specify one or more values:

var defaults = {
  property: 'all',
  duration: '1s',
  timing: 'ease-in-out',
  delay: '1s'
};

Up next comes the crux of our plugin—it returns the result of this function:

  return function (css) {
     css.walkRules(function (rule) {
       var transitionRule;
       var transitionValues = [];
       var index = -1, node;
       var attributes = /^(property|duration|timing|delay)$/;

We walk through each rule using css.walkRules—it sets up a number of variables and an array; we also set a search string that will be used to find any instance of our transition properties.

If we find a suitable instance of our property, we then clone it, adding the property name transition before it. We then work through each of up to four properties that may be set, joining them together into the final transition declaration:

       while (node = rule.nodes[++index]) {
        if (attributes.test(node.prop)) {
          transitionRule = transitionRule || node.cloneBefore({ prop: 'transition' });
           var transValues = postcss.list.space(node.value);
           transitionValues.push(transValues.join(','));
           node.remove();
           --index;
         }
       }
       transitionRule.value = transitionValues.join(' ');
    });
  };
});

Let's move on. Our first example was a straightforward plugin; although it does need some further development (as indicated in Testing our plugin), it still serves a useful purpose. In our next example, we'll take a different approach: we will use an existing plugin as a basis for our new version. This plugin, unlike the first one, will not see the light of day in GitHub, though—we'll explore the reasons for this, and more, as part of our next exercise.