Styling a Landing Page with PostCSS
Why do we need PostCSS?
We already have Sass, LESS, and Stylus — why do we need another pre-processor like PostCSS?
Sass has a syntax of writing styles which is unique to Sass while PostCSS does not impose any syntax for writing styles — it is more of a tool that transforms CSS. PostCSS relies on a catalog of plugins to do the actual transformation. The plugins are written in JavaScript and the input CSS is converted into a tree which the plugins transform. PostCSS converts the final transformed tree back to CSS.
Back to the original question. Why do we need PostCSS?
PostCSS is faster, modular, and more flexible than other existing pre-processors.
1. Faster than Sass
The PostCSS github page has performance benchmarks. The benchmark results are shown below.
Clearly, the winner is PostCSS — it is twice as fast as Sass.
2. Modular
The strength of PostCSS is its plugin ecosystem. The PostCSS catalog has several categories of plugins including Color, Fonts, Future, Grids, Images, Media-queries, and Sass. Each category has several plugins within it.
PostCSS converts the initial CSS into an Abstract Syntax Tree (AST), and allows each plugin to do its transformation. When all transformations are complete, it converts the final tree to an output CSS which can be rendered in the browser. Since each plugin does only a small but specific transformation, PostCSS is modular.
3. Flexible
PostCSS is flexible. It does not have any specific syntax by itself. Instead, it supports features available in other pre-processors like Sass. There is a plugin category called Sass. Most of the popular Sass features are supported by these plugins.
simple-vars
is a plugin that supports Sass-like variables.simple-extend
is a plugin that "extends" a CSS class.nested
is a plugin that unwraps nested rules.mixins
is a plugin that enables mixins.
There is also a less-engine
plugin that transforms Less to CSS.
Apart from supporting existing syntaxes, PostCSS allows anybody to author a PostCSS plugin and publish it to the catalog.
Getting started with PostCSS
PostCSS has a command line interface (CLI) which can be installed via NPM.
npm install -g postcss-cli
PostCSS transforms input CSS to the desired output CSS using plugins. Autoprefixer
is a popular plugin that adds vendor prefixes to CSS rules. The below input CSS needs to be transformed with vendor prefixes.
p {
display: flex
}
Install Autoprefixer using NPM.
npm install -g autoprefixer
The command line script to run PostCSS requires the following parameters.
--use
Specifies a plugin.--output
Specifies an output file.
postcss --use autoprefixer --output output.css input.css
The output CSS produced has all the vendor prefixes applied.
p {
display: -webkit-box;
display: -ms-flexbox;
display: flex
}
Next, we move on to using PostCSS within our project build. The popular build tools are Webpack, Gulp, and Grunt. For this tutorial, we will learn how to use PostCSS with Webpack.
Build a simple landing page
The landing page that we are going to build is quite simple. It has a header, footer, and content. The content is three blocks floated horizontally. Each block has its own background image. The text within the block is centered. The final landing page is shown below.
Bootstrap the project with Webpack
We will start by creating a landing page project.
npm init
The npm init
command will create a package.json. Add webpack
and webpack-dev-server
as dependencies.
npm install webpack webpack-dev-server --save-dev
Running the webpack-dev-server
command will run a web server which will open the index.html page at http://localhost:8080. The contents of the index.html is given below.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>PostCSS Demo</title>
<script src="main.js"></script>
</head>
<body>
<div class="header">
PostCSS Demo
</div>
<div class="row">
<div class="col-fast">
Fast
</div>
<div class="col-modular">
Modular
</div>
<div class="col-flexible">
Flexible
</div>
</div>
<div class="footer">
PostCSS is awesome!
</div>
</body>
</html>
We will use CSS to style the index page. Add a CSS file main.css
as follows.
body {
font-family: Monaco;
width: 640px;
margin: auto;
}
.header {
padding: 20px;
font-size: 1.5em;
}
.row {
padding: 20px;
}
.footer {
padding: 20px;
font-size: 0.8em;
text-align: right;
}
Webpack uses an entry JavaScript file to kick-start the build process. Add index.js
which will serve as the entry point of Webpack build.
require("./main.css");
Webpack uses the webpack.config.js
file for configuring the build process. Define the Webpack configuration as follows.
module.exports = {
entry: './index.js',
output: {
filename: 'main.js'
},
module: {
loaders: [
{
test: /\.css$/,
loader: "style-loader!css-loader"
}
]
}
}
The main.css
file that is processed by css-loader
module. The output of thecss-loader
is processed by another module style-loader
. The style-loader
embeds the output CSS into the head tag of index.html
.
Install the two loaders using npm.
npm install css-loader style-loader --save-dev
On running webpack-dev-server
, the landing page can be viewed at http://localhost:8080. The screenshot of the landing page is shown below.
Using PostCSS to style the page
Sass and Less are popular because we can define variables that can be reused across multiple styles. For our landing page, we can add a background color to the header and footer.
$primaryBackColor: #0047AB;
.header {
background-color: $primaryBackColor;
}
.footer {
background-color: $primaryBackColor;
}
We can add a border to the middle section with the same color as $primaryBackColor
.
.row {
border: 2px solid $primaryBackColor;
}
The text color for header and footer can be abstracted to a variable $primaryTextColor
as follows.
$primaryTextColor: #FFF;
.header {
color: $primaryTextColor;
}
.footer {
color: $primaryTextColor;
}
To make the CSS example above to work, we need to use postcss-loader
as a Webpack module. In addition, we need to use postcss-simple-vars
plugin.
npm install postcss postcss-loader postcss-simple-vars --save-dev
The Webpack configuration should have the following PostCSS settings.
module.exports = {
entry: './index.js',
output: {
filename: 'main.js'
},
module: {
loaders: [
{
test: /\.css$/,
loader: "style-loader!css-loader!postcss-loader"
}
]
},
postcss: function () {
return [require('postcss-simple-vars')];
}
}
After running webpack-dev-server
with the new Webpack configuration, we get a better looking landing page.
Reusing styles
Another plugin that is extremely useful is the postcss-simple-extend
plugin. The plugin defines placeholders for repetitive code. The three content blocks have similar CSS elements. The only difference is the background image. The CSS for a single block is as follows.
.col-fast {
width:180px;
height:360px;
font-size: 30px;
position: relative;
float: left;
display: flex;
align-items: center;
justify-content: center;
margin: 8px;
}
.col-fast::before {
content: ' ';
background-image: url('images/fast.jpg');
display: block;
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
z-index: 1;
opacity: 0.3;
background-repeat: no-repeat;
background-position: 50% 0;
background-size: cover;
}
To avoid repetitive code, the postcss-simple-extend can be used. We will install postcss-simple-extend
plugin along with a Webpack module url-loader
. The url-loader
plugin will process the background image.
npm install postcss-simple-extend url-loader --save-dev
The Webpack config for PostCSS needs to be modified as well.
postcss: function () {
return [
require('postcss-simple-vars'),
require('postcss-simple-extend')
];
}
The postcss-simple-extend
plugin has a define placeholder. We will define two placeholders for the block (col
) and the background image (col-before
).
@define-placeholder col {
width:180px;
height:360px;
font-size: 30px;
position: relative;
float: left;
display: flex;
align-items: center;
justify-content: center;
margin: 8px;
}
@define-placeholder col-before {
content: ' ';
display: block;
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
z-index: 1;
opacity: 0.3;
background-repeat: no-repeat;
background-position: 50% 0;
background-size: cover;
}
The placeholders can be used in multiple places by using @extend
statement.
.col-fast {
@extend col;
}
.col-fast::before {
@extend col-before;
background-image: url('images/fast.jpg');
}
.col-modular {
@extend col;
}
.col-modular::before {
@extend col-before;
background-image: url('images/modular.jpg');
}
.col-flexible {
@extend col;
}
.col-flexible::before {
@extend col-before;
background-image: url('images/flexible.jpg');
}
Nesting styles
There are three block elements which are floated to the left of each other. If the float is not cleared, the landing page won't look pretty. The :after
psuedo-element can be used to clear the float.
.row {
padding: 20px;
border: 2px solid $primaryBackColor;
background-color: $contentBackColor;
&::after {
content: ".";
visibility: hidden;
display: block;
height: 0;
clear: both;
}
}
To use nested styles in your CSS, add the postcss-nested
plugin to the webpack config.
npm install postcss-nested --save-dev
The plugin should be included in the Webpack config.
postcss: function () {
return [
require('postcss-simple-vars'),
require('postcss-nested'),
require('postcss-simple-extend'),
];
}
The floating blocks can also be nested as follows.
.col-fast {
@extend col;
&::before {
@extend col-before;
background-image: url('images/fast.jpg');
}
}
Summary
PostCSS does not have a syntax by itself. It allows various plugins to be included in the build process. Each plugin supports an extended CSS syntax. The autoprefixer
plugin adds vendor prefixes to CSS. The postcss-simple-vars
plugin allows reuse of CSS rules. The postcss-simple-extend
allows reuse of CSS blocks. The postcss-nested
plugin allows nested CSS styles. There are around 200 plugins in the PostCSS ecosystem. It is easy to author your own plugin.
There is an accompanying github project for the tutorial. You can also check out other tutorials related to this topic like: Compiling SASS and PostCSS with Angular CLI, and Building a flipper using React JS and LESS CSS.
Nice article!. It’s posible to communicate with your for learning about reactjs e2e tests and UT?