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

Dissecting the architecture of a standard plugin

Creating a PostCSS plugin is a straightforward process—the beauty of PostCSS is that we as developers are free to design and construct any plugin we desire; it does mean that not every plugin will be of the same quality as others!

This aside, the recommended way to construct any PostCSS plugin is to use the boilerplate code, which is available from https://github.com/postcss/postcss-plugin-boilerplate; we can see an example of it in this screenshot:

Dissecting the architecture of a standard plugin

If we explore the source code for any PostCSS plugin hosted in GitHub, there will be a host of different files present; not all of them will be the same for each different plugin!

Nonetheless, if we delve in deeper, there are some files we would expect to see as part of the architecture of any plugin; they are as follows:

  • index.js: This contains the main functionality for each plugin
  • package.json: This is used to configure and manage locally installed NPM packages
  • test.js: This contains the tests required to ensure the plugin works as expected

Let's explore these in more detail, beginning with index.js.

Exploring index.js

The crux of any plugin centers around index.js—we start with a reference to PostCSS (as a dependency for our plugin); this is followed by the exports function, which exposes functionality to anyone using the plugin:

var postcss = require('postcss');
 
module.exports = postcss.plugin('myplugin', function(options) {

  return function (css) {
    options = options || {};
         
    // Processing code will be added here
  }
});

Discovering package.json

Next up, we have package.json—this is used to configure and manage locally installed Node packages; given that PostCSS is based on Node.js, we will see something akin to this for any plugin installed as part of the PostCSS ecosystem:

{
  "name": "PLUGIN_NAME",
  "version": "0.0.0",
  "description": "PostCSS plugin PLUGIN_DESC",
  "keywords": [
    "postcss",
    "css",
    "postcss-plugin"KEYWORDS
  ],

The first section contains some basic details about the plugin name, description, and version. If we look through the package.json file, it's not difficult to spot a number of keywords in capitals—at first glance, one might be mistaken for thinking that it renders as invalid JSON.

There is a reason for this—one of the steps for using this boilerplate plugin is to run a script that will replace these keywords with information; the script will transform this into valid JSON. This is something we will cover in more detail later, in the Creating a transition plugin section. For now, assume that this file will be converted to valid JSON during the build process.

Moving on, we then store the name of the author, the plugin's license, and where we can get the source or file bugs relating to the plugin:

  "author": "AUTHOR_NAME <AUTHOR_EMAIL>",
  "license": "MIT",
  "repository": "GITHUB_NAME/PLUGIN_NAME",
  "bugs": {
    "url": "https://github.com/GITHUB_NAME/PLUGIN_NAME/issues"
},
"homepage": "https://github.com/GITHUB_NAME/PLUGIN_NAME",

This section is the most critical—the dependencies section stores details of any dependencies, when used in production; the devDependencies section takes care of dependencies when working in a development environment:

  "dependencies": {
    "postcss": "^5.0.10"
  },
  "devDependencies": {
    "ava": "^0.7.0",
    "eslint": "^1.10.2"
  },
  "scripts": {
    "test": "ava && eslint *.js"
  }
}

A key guideline given by the PostCSS team is that every plugin should be tested—this should always be a given, to help ensure we are creating something that is solid and not likely to cause issues for our users. A part of the boilerplate code contains a suitable test script for this purpose, so let's take a quick look at it now.

Exploring test.js

The third element that is key to any plugin is the test—this should be stored in test.js, and will look similar to this:

import postcss from 'postcss';
import test from 'ava';

import plugin from './';

function run(t, input, output, opts = { }) {
  return postcss([ plugin(opts) ]).process(input)
    .then( result => {
      t.same(result.css, output);
      t.same(result.warnings().length, 0);
    });
}

/* Write tests here
test('does something', t => {
  return run(t, 'a{ }', 'a{ }', { });
});
*/

We will cover this part in more detail later in this chapter, in the Testing and submitting a plugin section—for now, let's get stuck in to creating a PostCSS-based plugin. We'll start with a quick look at the API, before diving into creating a plugin that applies a specific font stack based on a chosen font, and adds updated declarations if one of those fonts needs to be imported into our site.

With the framework in place, we can then build up our plugin using the PostCSS API; this contains a number of classes, modules, and methods that we can use. The key function in the API is of course postcss—this is the main entry point for PostCSS and is required for all plugins:

var postcss = require('postcss');

Let's take a quick look through what else is available in the API, beginning with the Vendor module.

The Vendor module

This module contains helpers for working with vendor prefixes—we can initiate it using this object:

var vendor = postcss.vendor;

The module contains two methods, as shown in the table:

Module

Format

Value returned

vendor.prefix

String

The vendor prefix extracted from an input string:

// prefix extracted = '-webkit-'
var vp = postcss.vendor;
vp.prefix('-webkit-clip-path')

vendor.unprefixed

String

The input string stripped of its vendor prefix:

// value extracted = 'tab-size'
var vp = postcss.vendor;
vp.unprefixed('-moz-tab-size')

The List module

This module contains helpers to safely split lists of CSS values, whilst preserving parentheses and quotes. We can initiate it using this object:

var list = postcss.list;

The module contains two methods, as shown in the table:

Module

Format

Designed to split

list.space

String

Space-separated values (such as those for background, border-radius, and other shorthand properties):

// expected result:
// ['1px', 'calc(10% + 1px)']
var ls = postcss.list;
ls.space('1px calc(10% + 1px)')

list.comma

String

Comma-separated values (such as those for transition-* and background properties):

// Expected result:
// ['black', 'linear-gradient(white, black)']
var ls = postcss.list;
ls.comma('black, linear-gradient(white, black)')

Classes available in the API

Once the PostCSS object has been defined as a dependency in our plugin, we can begin to manipulate its contents—for this purpose, there are a number of classes available to assist, as shown in this table:

Name of class

Role within plugin

Processor

Creates a Processor instance, initializes any plugins, then uses this instance on CSS files as specified in the configuration.

LazyResult

Acts as a promise proxy for the result of PostCSS transformations.

Promises are a key part of working with Node.js—if you are not familiar with this concept, take a look at https://www.promisejs.org/ for a detailed explanation.

Result

Provides the result of any PostCSS transformations.

Warning

Allows a user to manage a warning within the plugin.

CssSyntaxError

Allows a user to retrieve any errors for broken CSS, generated by the CSS parser.

Input

Represents the source CSS being manipulated by PostCSS plugins.

Nodes available in the API

Of course, we cannot manipulate content from within a PostCSS plugin without having access to each CSS node—the API contains a group of useful nodes to help with parsing and manipulating content:

Node

Represents

Root

A CSS file and its parsed nodes:

var root = postcss.parse('a{color: darkred}');
root.type         //=> 'root'
root.nodes.length //=> 1

AtRule

An @-based rule in CSS, such as @media print {…}

Rule

A CSS rule, containing a selector and declaration block:

var root = postcss.parse('h1{}');
var rule = root.first;
rule.type       //=> 'rule'
rule.toString() //=> 'h1{}'

Declaration

A CSS declaration:

var root = postcss.parse('a{color: darkred}');
var decl = root.first.first;
decl.type       //=> 'decl'
decl.toString() //=> 'color: darkred'

Comment

A comment between declarations or statements (in both rules and @-rules):

var root = postcss.parse('a { color: /* inner */ darkred; /* outer */ }');
var decl    = root.first.first;
var comment = root.first.last;

comment.type //=> 'comment'
decl.between //=> ': /* inner */'

Methods available in the API

A key role of a plugin is to navigate through each node to help determine if it should perform some action; the API contains a number of methods to assist with parsing nodes:

Method group

Purpose

Nodes

These methods are for working with each CSS node—this includes methods such as the following:

  • node.type: returns a string representing the node type
  • node.parent: returns the parent node as a string
  • node.next() or node.prev(): returns the next or previous child of a node's parent.

More details are available at https://github.com/postcss/postcss/blob/master/docs/api.md#nodes-common-methods

Containers

These methods contain methods for working with children in a container node—this includes methods such as the following:

  • container.nodes: returns an array containing the container's children.
  • container.first: return the container's first child node.
  • container.last: return the container's last child node.

More details are available at https://github.com/postcss/postcss/blob/master/docs/api.md#containers-common-methods

The main site contains details and examples of all of the methods and classes available within the API—it is worth taking time to familiarize yourself with the options available.

Tip

Details for each method or class are available on the PostCSS API page at https://github.com/postcss/postcss/blob/master/docs/api.md

Okay, enough with theory: on we go! Let's change tack and put some of what we've just learnt to good use by constructing a couple of plugins for PostCSS. These will use a real mix of the API commands that we've briefly looked at earlier in this chapter; our first demo centers around a shorthand plugin for creating transition statements within CSS rules in a style sheet, so let's get stuck in and see how it works.