Post & Pre Processing CSS

Hello, reader. On the way to learning the layout you grasped CSS and want to move on? Then you under the cat. Careful, a lot of code.

In this article I will review the preprocessors and postprocessor (s?).

I will not go into details about CSS, implying that you already know it. Classes will be called in BEM notation. Also, I will not go into the installation and configuration of everything I’m writing about, but I will nevertheless leave links that you can follow and learn how to do it yourself.

Let's start with preprocessors.

Preprocessors


What is a preprocessor outside of the CSS context? Vicki knows the answer.

What is a preprocessor in the context of CSS? In our case, the preprocessor is a program that is given a code written in the preprocessor language, and at the output we get the CSS, which we can give to the input of our browser.

What are the preprocessors? There are several representatives, for example: Sass (.sass, .scss), Less (.less) and Stylys (.stylus).
Also among the preprocessors, you can separately select PostCSS (or rather, its SugarSS parser and PreCSS plugin). Looking far ahead, I will say that yes, PostCSS is not only a postprocessor.

I will do a review on the example of Sass. Or rather, on its new syntax - SCSS, since it is closer to CSS than the old syntax. Let's start with the features that add preprocessors and which are not in CSS, and finish with the problems to be solved.

Opportunities


Variables


//style.scss
$color: #fff;
span {
    color: $color;
    background: $color;
}
//style.cssspan {
    color: #fff;
    background: #fff;
}

The utility of variables is hard to overestimate. Now you can give meaningful names to colors ($ tomato: rgb (255,99,71)), calculate values ​​not through constants, but through variables (height: $ body_height - $ footer_height) and many more. Many may argue that there are variables in CSS. But Can I Use says that there is no support for IE (and for obvious reasons it is not expected).

Nesting


//style.scss.chat-area {
    width: 40%;
    &__button { // & - указатель на текущий селектор(в данном случае & = .chat-area)
       display: inline-block;
       height:36px;
       width: 10px; 
    }
    a {
        color: red;
    }
}
//style.css.chat-area {
    width: 40%;
}
.chat-area__button {
    display: inline-block;
    height:36px;
    width: 10px; 
}
.chat-areaa {
    color: red;
}

At the beginning of the article I referred to BEM. In this example, the element with the chat-area class is a block. In case there is a sudden need to rename it, then now it will be possible to do it in one place, and this becomes a chore if there are several dozens of selectors that contain the name of a block in one file. I also want to note that this is a kind of protection against typos, because the name of the block is written once.

Mixins


//style.scss
@mixin border-radius($radius) {
     -webkit-border-radius: $radius;
        -moz-border-radius: $radius;
         -ms-border-radius: $radius;
             border-radius: $radius;
}
.box {
    @include border-radius(10px);
}
//style.css.box {
     -webkit-border-radius: 10px;
        -moz-border-radius: 10px;
         -ms-border-radius: 10px;
             border-radius: 10px;
}

Mixins are one of the most difficult topics to understand. Roughly speaking, mixin is a function that accepts arguments and applies rules depending on these arguments to a given selector. In this example, the border-radius mixin has been applied to the .box selector.

Additional functions


//style.scss
$color: #202020;
h1, h2 {
    color: lighten($color, 40%);
}
//style.cssh1, h2 {
    color: #868686;
}

Mostly new features make it easier to work with color. For example, the function lighten lightens the color by a given number of percent (the opposite function is darken).

Solvable problems


Modularity


The problem with standard import is that it creates an additional request to the server, and this is an expensive operation. It would be nice if the import immediately inserted into the source file all the text being imported, wouldn’t it?

Somehow, before, there were no preprocessors, and the problem had to be somehow solved. For example, you can write all the code in one file.

What it looks like
/* сброс умолчаний *//* общие стили *//* шапка *//* основная часть *//* футер *//* страница печати *//* мобильная версия */

Как это выглядит на самом деле
/* сброс умолчаний *//* общие стили *//* шапка *//* основная часть *//* футер *//* страница печати *//* мобильная версия *//* какие-то правки *//* новая страница *//* ещё какие-то правки *//* стили новой шапки *//* скопированные стили  *//* хотфиксы *//* пасхалка от разработчика *//* наработки от стажера *//* стили нового футера */



However, we have preprocessors and they will solve this problem for us. The preprocessor redefines the standard import and now, instead of a request to the server, it inserts the import into the source file, just as I wanted.

//style.scss
@import"selector1";
@import"selector2";
//selector1.scssspan {
  color: white;
}
//selector2.scssdiv {
  color: gold;
}
//style.cssdiv {
 color: gold;
}
span {
 color: white;
}

Please note that the source files have been converted to one. One request to the server for statics - one answer.

Inheritance


<sarcasm> We have classes, but no inheritance, how can that be? </ sarcasm>. Now it is possible to select the so-called "template selectors" and expand other selectors with them.

// style.scss
%equal-heights { // шаблонный селектор
    height: 100%;
}
%message { // шаблонный селектор
    padding: 10px;
}
.success {
  @extend %message; color: green;
}
.error {
  @extend %message; color: red;
}
// style.css.success, .error {
    padding: 10px;
}
.success {
    color: green;
}
.error {
    color: red;
}

The beauty of the template selectors is that they do not fall into the generated styles. The% select-heights template selector was not involved in the code in any way and did not leave any trace in CSS. The% message selector is reflected in the form of rules for selectors that have expanded it. It is possible to inherit from the usual selectors, but it is preferable to use the template, so that there is no excess garbage.

Formatting


After the code is written, it needs to be formatted (for production to compress). You can do this with the help of collectors on the type of webpack, but you can also use standard tools.

In total, Sass has 4 types of formatting.

//expandedspan {
    color: gold; 
    display: block;
}
div {
    color: red;
}
//nestedspan {
     color: gold; 
     display: block; }
div {
 color: red; }
//compactspan { color: gold; display: block; }
div { color: red; }
//compressedspan{color:gold;display:block}div{color:red}

expanded - Most similar to human-written code.
nested - Approached the format of the old syntax. Readability is not lost, but this is a holivarny question.
compact - Still retains readability, but already with difficulty. Useful for determining by eye the number of selectors in a project.
compressed - A completely unreadable format. All characters that can be deleted are deleted. Suitable for "feeding" the browser.

P.S


I did not understand some of the features added by Sass. For example, cycles or features of arithmetic operators . I will leave them to you for self-examination.

Postprocessors


Having dealt with preprocessors, we proceed to postprocessors.

In the context of Css, the postprocessor is essentially the same as the preprocessor, but the input to the postprocessor is not code written in the preprocessor language, but also css. That is, the postprocessor is a program for the input of which is given css, and the output is css. It is not very clear why this is necessary.

I will explain with a concrete example of how PostCSS works - the only representative of post-processors in the context of css.

PostCSS out of the box doesn't actually do anything with CSS. It simply returns the file that was given to it. Changes begin when plugins connect to PostCSS.

The whole cycle of PostCSS can be described as:

  • The source file is given as input to PostCSS and parsed.
  • Plugin 1 does something
  • ...
  • Plugin n does something
  • The result is converted to a string and written to the output file.

Consider the main plug-ins that exist in the PostCSS ecosystem.

Plugins


Autoprefixer


This plugin is so popular that many people think that they use this plugin, but they don’t use PostCSS. They are wrong.

//in.cssdiv {
    display: flex
}
//out.cssdiv {
    display: -webkit-box;
    display: -webkit-flex;
    display: -moz-box;
    display: -ms-flexbox;
    display: flex
}

Autoprefixer adds browser prefixes to your rules. Indispensable and one of the most important plugins, from which the history of PostCSS began. You can even say that it makes sense to put PostCss just for the sake of this plugin.

Preset env


//in.css
@custom-media --med (width <= 50rem);
@media (--med) {
 a:hover {
    color: color-mod(black alpha(54%));
  }
}
//out.css
@media (max-width: 50rem) {
   a:hover  {
     color: rgba(0, 0, 0, 0.54);
   }
 }

PostCSS Preset Env adds features that are only discussed in the drafts of css developers. In this example, the @ custom-media directive was implemented, as well as the color-mod function. Start using future css today!

CSS Modules


All of these BEMs are not for you, but is there still a problem with class name conflicts? Then PostCSS offers another solution.

//in.css.name {
 color: gray;
}
//out.css.Logo__name__SVK0g {
 color: gray;
}

CSS Modules changes the class names for a certain pattern (everything is customizable). Now we do not know in advance the name of the class, because it is determined dynamically. How now to put down classes to elements if we do not know them in advance? Combining PostCSS, Webpack and ES6 can offer this solution:

import'./style.css'; // раньшеimport styles from'./style.css'; // сейчас

Now we do not just import a file with styles (for example, in the component's React file) and substitute the values ​​known in advance to us, but import some object. The keys for this object are the original selectors, and the values ​​are the converted ones. That is, in this example, styles ['name'] = 'Logo__name__SVK0g'.

Short


//in.css.icon {
 size: 48px;
}
.canvas {
 color: #abccfc#212231;
}
//out.css.icon {
 width: 48px;
 height: 48px;
}
.canvas {
 color: #abccfc;
 background-color: #212231;
}

PostCSS Short adds a bunch of shorthand entries for various rules. The code becomes shorter, and therefore there is less room for errors. Plus increases readability.

Auto reset


//in.cssdiv {
 margin: 10px;
}
a {
 color: blue;
}
//out.cssdiv, a {
 all: initial;
}
div {
 margin: 10px;
}
a {
 color: blue;
}

PostCSS Auto Reset allows us not to create a separate file with a reset of all styles. The plugin creates one big selector for all selectors, where it places rules that reset all styles. By default, only the all rule is created with the initial value. This is useful in combination with the postcss-initial plugin , which in turn turns this rule into a footer of rules for 4 screens. However, everything can be configured and reset for example:

//out.cssdiv, a {
 margin: 0;
 padding: 0;
}
div {
 margin: 10px;
}
a {
 color: blue;
}

Remember in the beginning of the article I said that PostCSS is not only a postprocessor?

PostCSS - preprocessor?


Consider one parser and one plugin, after which you change your current opinion about PostCSS.

Sugarss


//in.sss.parentcolor: white.parent > .childcolor: black
//out.css.parent {
  color: white
}
.parent > .child {
  color: black
}

SugarSS is a parser (not a plugin!), Which is based on indents , not on curly braces, as standard. It has a separate extension ".sss". Code written using SugarSS is similar in style to the old Sass syntax, but without its lotions like variables, mixins, inheritance, and so on.

You guessed it would add the next plugin?

PreCSS


//in.sss
$color: black.parent.childcolor: $color
//Результат работы SugarSS
$color: black;
.parent {
 .child {
   color: $color
 }
}
//out.css.parent.child {
   color: black
}

PreCSS adds the very possibilities of preprocessors about which are written in the first half of the article.

And why is PostCSS no longer a preprocessor?

Stylelint


About Stylelint already written quite a lot. He came to this review because he uses PostCSS as a parser of lines of CSS files. Suppose we have such a file.

a {
 color: rgb(1, 1, 1)
}
div {
 color: rgb(0, 0, 0)
}

Here is its output for the current file:

 2:21    Expected a trailing semicolon              declaration-block-trailing-semicolon
 6:21    Expected a trailing semicolon              declaration-block-trailing-semicolon
 7:1     Unexpected missing end-of-source newline   no-missing-end-of-source-newline

The utility of this tool is quite difficult to overestimate.

findings


Preprocessors add a lot of new functionality that is not in CSS. Once you have tried it, you will hardly return to regular CSS.

PostCSS is much closer to the original CSS than preprocessors, but nevertheless, with certain plug-ins connected, it can have the same functionality (and even a similar syntax). Newbie layout makers can typeset without even thinking that they are not layout on pure CSS. Some plugins (for example Autoprefixer) have no analogues in the preprocessor world.

No one bothers to use preprocessors and PostCSS in conjunction. The option is pretty good for projects that already use preprocessors and have a place to live.

For new projects, I would advise using only PostCSS. Are web designers accustomed to the preprocessor syntax? Install the PreCSS plugin and the SugarSS parser. Need cross-browser compatibility? Put the plugin Autoprefixer. No longer need cross-browser compatibility (for example, your project was wrapped in an electron and it became desktop)? Just uninstall Autoprefixer! With PostCSS, you can, as with the help of the designer, build exactly what your project needs.

Also popular now: