An overview of the CSS preprocessor LESS.
Including code samples for creating mixins, variables, math, colors, patterns, guards, scope, and namespaces.
2. “When I am working on
a problem, I never think
about beauty, but when
I have finished, if the
solution is not beautiful,
I know it is wrong.
Buckminster Fuller
http://www.flickr.com/photos/21680590@N06/4654423909/
16. /* Windows? ------------------------------
Try tools like WinLess or SimpLESS. You can also install less builders
for most code editors like Sublime Text 2 and Eclipse (see references.)
http://winless.org/ http://wearekiss.com/simpless
*/
install
install brew $ ruby <(curl -fsSkL raw.github.com/mxcl/homebrew/go)
install node $ brew install node
install npm $ curl http://npmjs.org/install.sh | sh
install less $ npm -g install less
17. .less files
/* Notes: ------------------------------
To get started, all you have to do is change your .css file
extensions to .less files.
One of the strengths of LESS over competing CSS
preprocessors, is that .less files are valid CSS files and
vice versa. This makes learning the language easier, and
reading LESS files a no brainer for new comers.
*/
18. /* Notes: ------------------------------
The compress option will remove all whitespace. The yui-compress option
will also remove all line-breaks.
*/
using the less cli
$ lessc [options] input.less [output.css file]
options:
-compress
-yui-compress
20. /* Notes: ------------------------------
The less compiler will find syntax errors as well as errors with
undefined variables. You can also try csslint on your output files, but
be ready to get your feelings hurt.
*/
debugging
html {
font-size 100%;
}
$ lessc source.less
$ ParseError: Syntax Error on line 2 in source.less:2:0
1 html {
2 font-size 100%;
3 }
21. /* Inner Workings: ------------------------------
Node compiles matching .less files when it receives a URL request for
a .css resource. For example if you hit http://localhost/style.less Node
looks for a style.less file in the same path and compiles it into a
style.css file on the fly and returns it to you.
*/
node.js & less middleware
app.configure(function(){
app.use(require('less-middleware')({
src: __dirname + '/public',
compress: true,
yuicompress: true, // one or the other
optimization: [0,1,2]
}));
}
23. /* Tips: ------------------------------
LESS will import the contents of files and concatenate them into the one
file, unless you specify the .css extension. If you leave out the extension
LESS looks for a .less file, not a .css file.
*/
imports
@import “reset.css”; // statement is left alone in output
@import “reset.less”; // processed and contents imported into output
@import “reset”; // same as above since the “.less” is optional
25. /* Notes: ------------------------------
Nesting in LESS results in scope. We will cover scope in a few minutes.
Nesting order, spacing, and tabs are purely for readability. So you can
also do things like: li > a.selected {} though it is not recommended.
*/
nesting
#navigation {
li {
display: inline-block;
&:first-child { padding: 5%; }
> a {
&.selected { color: gray; }
&:hover { background: red; }
}
}
26. /* Notes: ------------------------------
Keep in mind that in less, variables are actually constants, so they can
only be defined once.
It’s good practice to line up your variable columns for good readability.
*/
variables
@base-font-size: 16;
@base-padding: 5%;
@base: “/images”;
@light-gray: #D3D3D3;
27. /* Hint: ------------------------------
Most LESS aware editors like Coda 2 will suggest and auto-complete your
defined variable names as you type.
*/
using variables
.box {
padding: @base-padding;
background-color: @light-gray;
}
29. /* Details: ------------------------------
Embed and use variables using the @{variable} syntax, like PHP or Ruby.
*/
string interpolation
@base: “/images”;
@light-gray: #D3D3D3;
body {
background: @light-gray url("@{base}/bg.png");
}
30. /* Details: ------------------------------
Tilde escapes the value. You can also use the e() function if you like.
Use it for value calculations, otherwise the output becomes font-size:
“20px” not 20px. Also use the ~ with IE specific rules like filter.
*/
escaping strings
@base-font-size: 16;
body {
font-size: ~"@{base-font-size}px";
filter: e("ms:likesProprietaryCssStuff()");
}
32. /* Notes: ------------------------------
Basic math operations (+ - * /) are supported in less. What’s great is
that any CSS value, number, or color, plus any less variable can be
operated on. This includes things like %, em, px, etc.
More on color operations later in this presentation.
*/
math operations
@base-padding: 5%;
@gutter-padding: @base-padding * 2;
@light-gray: #D3D3D3;
@body-padding: @gutter-padding - 3; // 7%
@body-color: @light-gray / 4; // #353535
33. /* Notes: ------------------------------
Other Math functions like abs, max, min, random, etc. are not supported
at this time.
*/
math functions
@width-flexible: percentage( 650 / 960 ); // 67.70833333333334%
@width-round: round( @width-flexible ); // 1%
@width-ceil: ceil( @width-flexible ); // 1%
@width-floor: floor( @width-flexible ); // 0%
35. /* Notes: ------------------------------
Mixins are functions in less. They help you reuse css code.
Keep in mind that this .button mixin is actually is a basic CSS class in
LESS and will appear in your output file as such.
*/
mixins
.button {
! box-shadow: inset 1px 1px 5px 0px @light-gray / 2;
! -webkit-border-radius: 5px;
! -moz-border-radius: 5px;
! border-radius: 5px;
}
36. /* Notes: ------------------------------
The opening and closing parentheses are not required when calling a
simple mixin like this without parameters. You always do have to include
the semi-colon.
*/
using mixins
a {
.button;
}
/* The result will be */
a {
! box-shadow: inset 1px 1px 5px 0px @light-gray / 2;
! -webkit-border-radius: 5px;
! -moz-border-radius: 5px;
! border-radius: 5px;
}
37. /* Notes: ------------------------------
The first part of the parameter is the name and the second part is the
optional default value. Parameterized mixins are not included in the
resulting .css files by the LESS compiler.
*/
mixins with parameters
.ems(@size: @base-font-size, @base: @base-font-size) {
! @value: @size / @base;
! font-size: ~"@{value}em";
}
38. /* Notes: ------------------------------
Our mixin takes 2 paramters. We’ve made them both optional, so we can
also call the it using just .ems(24); or .ems(); or .ems; in this case.
It is good practice to provide default values in your mixin definitions.
*/
passing mixin parameters
.title {
! .ems(24, 16);
}
/* The result will be */
.title {
! font-size: 1.5em;
}
39. /* Notes: ------------------------------
When you call the .h1 mixin you will get the result from the ems mixin as
well as the bold font, assigned to your calling class.
*/
mixins calling other mixins
.heading {
! .ems(32);
! font-weight: 700;
}
h1 { .heading; }
/* The result will be */
h1 {
! font-size: 2em;
! font-weight: 700;
}
41. /* Notes: ------------------------------
If you just use the @arguments variable, it will spit out the values you
need based on what is passed in and what defaults you’ve set up, in the
order you defined them.
*/
the @arguments variable
.box-shadow(@x: 0, @y: 0, @blur: 1px, @spread: 1px, @color: #000){
! box-shadow: @arguments;
! -moz-box-shadow: @arguments;
! -webkit-box-shadow: @arguments;
}
42. /* Notes: ------------------------------
You can only leave out arguments at the end of an argument list, but not
the beginning. For example you can do .box-shadow(0px, 0px, 3px); but you
can’t do .box-shadow(0px, @light-gray / 2)
*/
using @arguments
.button {
.box-shadow(0px, 0px, 3px, 0px, @light-gray / 2);
}
/* The result will be */
.button {
box-shadow: 0px 1px 3px 0px #6a6a6a;
-moz-box-shadow: 0px 1px 3px 0px #6a6a6a;
-webkit-box-shadow: 0px 1px 3px 0px #6a6a6a;
}
44. /* Super Geeky stuff: ------------------------------
LESS first converts colors into the HSL (hue, saturation %, lightness %)
color-space, and then manipulates them at the channel level.
*/
colors
@green: #00FF00;
lighten(@green, 30%); // #99ff99 - 30% *lighter*
darken(@green, 30%); // #006600 - 30% *darker*
saturate(@green, 30%); // #00ff00 - 30% *more* saturated
desaturate(@green, 30%); // #262926 - 30% *less* saturated
45. /* Super Geeky stuff: ------------------------------
The mix function requires a weight argument between 0-100.
The fade functions always return rgba values, unless the color has hit a
max alpha, such as blue above, which can’t be made less transparent.
*/
more color functions
@blue: #0000FF;
@red: #FF0000;
fade(@blue, 50%); // rgba(0,0,255,0.5) - 50% transparency
fadein(@blue, 30%); // #0000ff - 30% *less* transparent
fadeout(@blue, 30%); // rgba(0,0,255,0.7) - 30% *more* transparent
spin(@blue, 30); // #7f00ff - 30 degrees larger hue
spin(@blue, -30); // #007fff - 30 degrees smaller hue
mix(@blue, @red, 50); // #800080 - a mid blend of @red and @blue
47. /* Notes: ------------------------------
Mixin changes behavior based on parameters.
The first mixin will only match if our @display-type variable has a value
of “block” and the second one will only run if is set to “inline”. The @_
argument matches any value.
*/
switch patterns
.switch-me (box, @color) { border-radius: 0; }
.switch-me (round, @color) { border-radius: 5px; }
.switch-me (@_, @color) { color: @color; }
color: @color;
.button { .switch-me(@display-type, 300px); }
// Output
.button {
display: block;
width: 300px;
}
48. /* Notes: ------------------------------
LESS inspects all defined mixin signatures and only applies the one(s)
that matches your called arity.
*/
switch on arity
.flex-box (@min) { min-width: @min; }
.flex-box (@min, @max) { min-width: @min; max-width: @max; }
.content {
.flex-box(200px, 800px);
}
// Output
.content {
min-width: 200px;
max-width: 800px;
}
52. /* Notes: ------------------------------
As you can see, LESS keeps block scope inside curly braces.
Note: Not to be confused with the scoped style attribute introduced in
HTML5.
*/
scope
@my-text-color: black;
section {
@my-text-color: gold;
header {
color: @var; // gold
}
}
footer {
color: @my-text-color; // black
}
54. /* Notes: ------------------------------
Namespaces allow for code organization and or encapsulation. You have
access to the @arguments variable as with mixins.
*/
namespaces
#lib {
.clear(@direction) {
zoom: 1;
&:after { content: ”00a0”; clear: @direction; display: block;
}
}
}
#wrapper {
#lib > .clear(both); // inserts our clear rules from the lib namespace
}
55. /* Notes: ------------------------------
Write helpful comments to help you find scoped mixins when debugging.
*/
comments
// Single line comments are not shown in the compiled output
/* Block level comments will be kept in the output */