There are many CSS preproccesors currently in the wild. They work creating a new language sweeted with syntactic sugar that either redefines CSS syntax or simply reuses it with some special meanings added. The document created is finally compiled so it can actually work on any browser.
LESS, as one of this preproccesors, uses the same syntax of CSS so the preprocessor can understand already existing CSS code; this existing code can actually work as a base for a new project. Even though the similar syntax, the preprocessor expects files with the extension .less to make its work.
Having said this, it should be noted that this is actually valid LESS code:
/* Just a CSS comment */
p {
color: blue;
font-size: 15px;
}
LESS lets you define variables (in the programming sense) which can be later referenced. Variables are defined prepeding their names with the @ character followed by a semicolon (just as a CSS property). Be aware that variables can only contain valid values of CSS properties i.e. bold is valid, 1px solid red too, but not color: red
/* Declaring a LESS variable */
@background: #fff;
@text: #333;
p {
color: $text;
background: $background;
}
Above code will output
p {
color: #333;
background: #fff;
}
Mixins come to solve how to define a full CSS rule (or group of rules). Plus they can also work as function taking arguments.
Mixins are defined like usual CSS class selector with the properties grouped inside curly brackets. Variables are defined between parenthesis after the mixin name.
/* A mixin in LESS */
.border_radius(@radius) {
moz-border-radius: @radius;
webkit-border-radius: @radius;
border-radius: @radius;
}
p {
.border_radius(5px);
}
Above code will output
p {
border-radius: 5px;
webkit-border-radius: 5px;
border-radius: 5px;
}
A mixin can define a default value for a variable
.border(@width: 1px) {
border: @width solid #000;
}
p {
.border;
}
/* CSS output */
p {
border: 1px solid #000;
}
Be careful when you define mixins that take no arguments cause they will be treated as classes by the preprocessor
.border_radius {
moz-border-radius: 5px;
webkit-border-radius: 5px;
border_radius: 5px;
}
This code will appear as is in the final output even if you don't use it anywhere. Best practice is to always add a pair of parenthesis (even if empty) to make sure your mixin is treated as one.
Nesting rules lets you actually write less by nesting a selector and its rules inside the rules of its parent. Less code and a good indentation can make code review easier.
/* Some nested rules in LESS */
aside {
color: #ccc;
font-size: 12px;
h3 {
color: #000;
font-size: 16px;
text-decoration: underline;
}
}
/* CSS output */
aside {
color: #ccc;
font-size: 12px;
}
aside h3 {
color: #000;
font-size: 16px;
text-decoration: underline;
}
Be careful not to abuse this feature. Some rules make look nice and easy to read in LESS but create some bloat in the CSS output.
/* IDs are unique so there should no need to declare the parent element */
#header {
#companylogo {
margin: 10px;
}
}
/* Bloated output */
#header #companylogo {
margin: 10px;
}
LESS lets you do math operations on any numeric value (even if it includes letters).
body {
margin: 20px/2;
border: ( 10px-5 ) solid blue; /* No need to worry about "px" */
color: #333+#333; /* In this case, the hash is mandatory */
}
Parenthesis are mandatory according to the spec in the case of the border property due to the characters after the numbers. Even so some compilers don't complain about it.
The following code will not be parsed as a math operation by LESS body { font: 1em/1.5 "arial", sans-serif; }
LESS can apply transformations to color using native functions.
lighten(@color, 10%); // return a color which is 10% *lighter* than @color
darken(@color, 10%); // return a color which is 10% *darker* than @color
saturate(@color, 10%); // return a color 10% *more* saturated than @color
desaturate(@color, 10%); // return a color 10% *less* saturated than @color
Check color functions specification for a complete list.
LESS allows you to organize a group of variables and mixins under an unique namespace. Namespaces are defined using the # followed by its name.
#gradients {
.horizontal(@start, @end) {
background: linear-gradient(top, @start 0%,@end 100%);
}
.vertical(@start, @end) {
background: linear-gradient(left, @start 0%,@end 100%);
}
}
body {
background-image: #gradients > .horizontal(#000, #fff;);
}
Variable resolution works like most programming languages i.e. variales are first looked up locally and if it has no success, in the upper scope.
@color: blue;
p {
@color: green;
color: @color;
}
/* And the paragraph turned green */
Have you noticed? Variables are variables, not constants.
There are two types of valid comments.
- The classic CSS comment
/* that will appear in the final output */ - The single-line comment
// that won't appear in the final output
Since it's probable that you will use a CSS minifier, just remember that you can use /*! a bang */ to prevent a comment from being deleted.
Importing external files inside other is done in much the same way as traditional CSS with the @import rule. Even so there is an important distinction to be discussed.
- Imported LESS files using
@import external.lesswill be parsed and concatenated in the final output. - Imported CSS files using
@import style.csswill not be parsed.
Since CSS is valid LESS, you can just rename external .css files to .less and get one big CSS file for production (and thus reduce HTTP requests).
Currently the LESS compiler breaks with an error if you try to import .less file that reside in a different directory.
Suppose you have a mixin that takes just one argument and you try to feed it a string containing a comma. It will produce an error preventing compile.
.myfont(@font) {
font-family: @font;
}
p {
.myfont(arial, verdana);
}
The solution is to escape the string surronding it with double quotes plus predecing it with the ~ characters.
p {
.myfont(~"arial, verdana");
}
This may come in handy too with multiple backgrounds
Official specs offers a javascript file that can be added to the head of the file for compilation inside the browser. The good part is that it's an easy way to test LESS. It even has an option to automatically reload your stylesheet. The bad is that you should not deploy it to production.
There are two really goods native apps for Windows that can compile LESS.
Both apps watch for any changes in the source and can minify the output too. Be aware to feed the apps that source file that actually import all other .less files.
This comes from personal experience using LESS in my computer.
Since the LESS compiler is written is Javascript, I've chosen to use Node.js to run it. You will also need npm, the node package manager, to retrieve and install the LESS compiler package.
sudo apt-get install node npm
After these two have been installed, we will install lessc package to get the compiler.
sudo npm install -g lessc
Now we can do lessc style.less style.css (first file is source, latter is destination).
I've also installed uglifycss to minify the output.
sudo npm install -g uglifycss
Be aware that when you call uglifycss the source and output file have to be diffent.
uglifycss style.css > style.min.css
To make it easier to run these two apps I use a [makefile](http://en.wikipedia.org/wiki/Make_(software) that executes them.
LESSFILES = less/style.less
CSSFILES = style.raw.css
COMPRESSEDCSS = style.css
compile:
lessc ${LESSFILES} ${CSSFILES}
uglifycss ${CSSFILES} > ${COMPRESSEDCSS}
rm ${CSSFILES}
Finally, to mimic the watch functionality I use the watch app to run the make command periodically.
$ watch make
Since it's more probable that you have PHP installed in your system, you can also try lessphp. This compiler works as a class that has to be included (providing on-the-fly compilation) but it also features a small php script to use it as a standalone application. The lessphp documentation explains how this two options work.
The console script can also be used as a replacement for the node.js less compiler in the make file:
plessc ${LESSFILES} > ${CSSFILES}
Again, as a personal experience, I've used some modules from Twitter Bootstrap. Instead of using the whole package, I just @import useful files like mixin.less that include CSS3 gradients and transformations.
I also use YUI Grids for layout. I rename to file to .less and import it into my project.
Normalize.css is another useful file to import.