6 Reasons You Should Use a CSS Preprocessor

April 16, 2019
LESS CSS preprocessor, advanced features in web development

CSS preprocessors are scripting languages that extend the default capabilities of CSS. They enable us to use logic in our CSS code, such as variables, nesting, inheritance, mixins, functions, and mathematical operations. CSS preprocessors make it easy to automate repetitive tasks, reduce the number of errors and code bloat, create reusable code snippets, and ensure backward compatibility.

Each CSS preprocessor has its own syntax that they compile into regular CSS so that browsers can render it on the client side. Currently, the three most popular and stable CSS preprocessors are LESS, Sass, and Stylus, however there are many smaller ones as well. CSS preprocessors all do similar things but in a different way and with their own syntaxes. Each of them has some advanced features unique to them and their own ecosystem (tools, frameworks, libraries) as well.

Today is about LESS.

1. @variables

Variables make your code easier to maintain by giving you a way to control those values from a single location:

// Variables
@link-color: #428bca; // sea blue
@link-color-hover: darken(@link-color, 10%);

// Usage
a,
.link {
  color: @link-color;
}
a:hover {
  color: @link-color-hover;
}
.widget {
  color: #fff;
  background: @link-color;
}
1.1 @nested selectors
.button {
  &-ok {
    background-image: url("ok.png");
  }
  &-cancel {
    background-image: url("cancel.png");
  }

  &-custom {
    background-image: url("custom.png");
  }
}

Result after compiling:

.button-ok {
  background-image: url("ok.png");
}
.button-cancel {
  background-image: url("cancel.png");
}
.button-custom {
  background-image: url("custom.png");
}

2. @imports

CSS @import makes another http request to fetch another stylesheet, while a Less @import grabs the content from inside your imported file and includes it within the compiled stylesheet. This means only one http request, allowing you to create partials and organize your css just that little bit better without any downsides!

A normal import will grab the contents of that file and dump it into the file asking for it. Super useful. Concatenating files is a vitally important feature of preprocessors.

/* Normal import */
@import "colors-or-whatever.less";

A (reference) import doesn’t do that. In fact, it doesn’t put anything at all into the file asking for it. The code in that file is just now ready to use, either by calling a mixin within it or extending a selector within it.

@import (reference) "https://s3-us-west-2.amazonaws.com/s.cdpn.io/18728/pure.less";

.my-button {
  &:extend(.pure-button all);
}

3. @mixins

Mixins copy all of the properties into a selector, which can lead to unnecessary duplication. Therefore you can use extends instead of mixins to move the selector up to the properties you wish to use, which leads to less CSS being generated.

.a, #b {
  color: red;
}
.mixin-class {
  .a();
}
.mixin-id {
  #b();
}

Result after compiling:

.a, #b {
  color: red;
}
.mixin-class {
  color: red;
}
.mixin-id {
  color: red;
}

4. @extend

Extend is a Less pseudo-class which merges the selector it is put on with ones that match what it references.

nav ul {
  &:extend(.inline);
  background: blue;
}
.inline {
  color: red;
}

Result after compiling:

nav ul {
  background: blue;
}
.inline,
nav ul {
  color: red;
}

5. @math

Math functions includes methods which are used for performing numeric operations such as round, square root, power value, modulus, percentage, etc.

@nav-height: 60px;

body {
	padding-top: @nav-height + 40px;
}

.nav {
	position: fixed;
	top: 0;
	width: 100%;
	height: @nav-height;

}

.one-third {  
	width: (100% / 3);  
}

Result after compiling:

body {
  padding-top: 100px;
}
.nav {
  position: fixed;
  top: 0;
  width: 100%;
  height: 60px;
}
.one-third {
  width: 33.33333333%;
}

6. @loops

One of the best things about LESS is that you can do loops and build classes dynamically.

The following example is to make dynamically classes, increments of 10. I could have written 10 classes, but this way is much nicer and easier to maintain.

.mixin-loop (@index) when (@index > 0) {
  .per-@{index}0 {
    display: inline-block;
    width: @index * 10%;
  }
  .mixin-loop(@index - 1);
}
.mixin-loop(10);

Result after compiling:

.per-100 {
display: inline-block;
width: 100%;
}
.per-90 {
display: inline-block;
width: 90%;
}
.per-80 {
display: inline-block;
width: 80%;
}
.per-70 {
display: inline-block;
width: 70%;
}
.per-60 {
display: inline-block;
width: 60%;
}
.per-50 {
display: inline-block;
width: 50%;
}
.per-40 {
display: inline-block;
width: 40%;
}
.per-30 {
display: inline-block;
width: 30%;
}
.per-20 {
display: inline-block;
width: 20%;
}
.per-10 {
display: inline-block;
width: 10%;
}