A linguagem dinâmica de estilos.

LESS estende CSS com comportamento dinâmico como variáveis, mixins, operações e funções. LESS roda tanto no cliente (Chrome, Safari, Firefox) quanto no servidor, usando Node.js e Rhino.

versão 1.3.0

Escreva um pouco de LESS:

@base: #f938ab;
.box-shadow(@style, @c) when (iscolor(@c)) {
  box-shadow:         @style @c;
  -webkit-box-shadow: @style @c;
  -moz-box-shadow:    @style @c;
}
.box-shadow(@style, @alpha: 50%) when (isnumber(@alpha)) {
  .box-shadow(@style, rgba(0, 0, 0, @alpha));
}
.box { 
  color: saturate(@base, 5%);
  border-color: lighten(@base, 30%);
  div { .box-shadow(0 0 5px, 30%) }
}

Inclua o less.js junto com seus estilos:

<link rel="stylesheet/less" type="text/css" href="styles.less">
<script src="less.js" type="text/javascript"></script>

Variáveis

Variáveis permitem que você especifique valores amplamente utilizados em apenas um local, possibilitando assim reutilizá-las por toda sua folha de estilos, realizando mudanças globais de maneira tão fácil como alterar apenas uma linha de código.

// LESS

@color: #4D926F;

#header {
  color: @color;
}
h2 {
  color: @color;
}
/* CSS Compilado */

#header {
  color: #4D926F;
}
h2 {
  color: #4D926F;
}

Mixins

Mixins permitem que você adicione todas as propriedades de uma classe em outra classe simplesmente incluindo o nome da classe como uma de suas propriedades. Assim como variáveis, mas para classes completas. Mixins também podem se comportar com funções, e receber argumentos, como mostrado no exemplo abaixo.

// LESS

.rounded-corners (@radius: 5px) {
  border-radius: @radius;
  -webkit-border-radius: @radius;
  -moz-border-radius: @radius;
}

#header {
  .rounded-corners;
}
#footer {
  .rounded-corners(10px);
}
/* CSS Compilado */

#header {
  border-radius: 5px;
  -webkit-border-radius: 5px;
  -moz-border-radius: 5px;
}
#footer {
  border-radius: 10px;
  -webkit-border-radius: 10px;
  -moz-border-radius: 10px;
}

Regras Aninhadas

Ao invés de construir longos nomes de seletores para especificar herança, em LESS você pode simplesmente aninhar seletores dentro de outros seletores. Isto faz com que a herança fique mais clara e as folhas de estilos menores.

          // LESS

#header {
  h1 {
    font-size: 26px;
    font-weight: bold;
  }
  p { font-size: 12px;
    a { text-decoration: none;
      &:hover { border-width: 1px }
    }
  }
}
/* CSS Compilado */

#header h1 {
  font-size: 26px;
  font-weight: bold;
}
#header p {
  font-size: 12px;
}
#header p a {
  text-decoration: none;
}
#header p a:hover {
  border-width: 1px;
}

Funções & Operações

Alguns elementos de sua folha de estilo são proporcionais a outros elementos? Operações permitem que você some, subtraia, divida e multiplique valores de propriedades e cores, dando a você o poder de criar relações complexas entre propriedades. Funções mapeam de um-para-um com código JavaScript, permitindo a você manipular valores como quiser.

        // LESS

@the-border: 1px;
@base-color: #111;
@red:        #842210;

#header {
  color: @base-color * 3;
  border-left: @the-border;
  border-right: @the-border * 2;
}
#footer { 
  color: @base-color + #003300;
  border-color: desaturate(@red, 10%);
}
/* CSS Compilado */

#header {
  color: #333;
  border-left: 1px;
  border-right: 2px;
}
#footer { 
  color: #114411;
  border-color: #7d2717;
}

Uso no lado do cliente

Vincule seus estilos .less com o atributo rel definido como ‘stylesheet/less’:

<link rel="stylesheet/less" type="text/css" href="styles.less">

Depois baixe o less.js no topo desta página, e o inclua no elemento <head> da sua página, desta forma:

<script src="less.js" type="text/javascript"></script>

Certifique-se de incluir suas folhas estilos antes do script.

Modo watch

Modo watch é uma característica do lado do cliente que permite que seus estilos sejam automaticamente atualizados assim que forem alterados.

Para ativá-la, acrescente “#!watch” na URL do navegador e depois atualize a página. Alternativamente, você pode rodar less.watch() diretamente do console.

Uso no lado do servidor

Instalação

A maneira mais fácil de instalar o LESS no servidor, é pelo npm, o gerenciador de pacotes do Node.js, desta forma:

$ npm install less

Uso

Uma vez instalado, você pode chamar o compilador pelo Node.js, assim:

var less = require("less");

less.render(".class { width: 1 + 1 }", function (e, css) {
  console.log(css);
});

que produzirá a saída

.class {
  width: 2;
}

você também pode chamar o analisador (parser) e o compilador manualmente:

var parser = new(less.Parser);

parser.parse(".class { width: 1 + 1 }", function (err, tree) {
  if (err) { return console.error(err) }
  console.log(tree.toCSS());
});

Configuração

Você pode especificar algumas opções para o compilador:

var parser = new(less.Parser)({
  paths: [".", "./lib"], // Caminhos de busca para as diretivas @import
  filename: "style.less" // Um nome de arquivo, para mensagens de erros melhores
});

parser.parse(".class { width: 1 + 1 }", function (e, tree) {
  tree.toCSS({ compress: true }); // Minificar (minify) a saida
});

Uso na linha de comando

Less possui um binário, que permite que você chame o compilador diretamente da linha de comando, assim:

$ lessc styles.less

Isto produzirá como saída o CSS compilado para stdout, você pode então redirecioná-lo para um arquivo a sua escolha:

$ lessc styles.less > styles.css

Para produzir o CSS minificado (minified), apenas passe a opção -x. Se você quiser se envolver mais com o processo de minificação, o YUI CSS Compressor também está disponível através da opção --yui-compress.

A Linguagem

Como uma extensão do CSS, LESS não é somente retrocompatível com CSS, mas as funcionalidades extras que ele adicona utilizam a sintaxe existente do CSS. Isso torna o aprendizado do LESS fácil e, em caso de dúvida, permite que você use a sintaxe regular de CSS como fallback.

Variáveis

Estes se auto explicam:

@nice-blue: #5B83AD;
@light-blue: @nice-blue + #111;

#header { color: @light-blue; }

Saída:

#header { color: #6c94be; }

Também é possível definir variáveis com um nome variável:

@fnord: 'I am fnord.';
@var: "fnord";
content: @@var;

Que compila para:

content: 'I am fnord.';

Na verdade as variáveis em LESS são “constantes”, pois elas só podem ser definidas uma vez.

Mixins

Em LESS, é possível incluir várias propriedades de um grupo de regras (ruleset) em um outro grupo de regras. Digamos que temos a seguinte classe:

.bordered {
  border-top: dotted 1px black;
  border-bottom: solid 2px black;
}

E queremos usar estas propriedades dentro de outros grupos de regras. Apenas temos que por o nome da classe dentro de qualquer grupo de regras que desejamos utilizar estas propriedades, como no exemplo:

#menu a {
  color: #111;
  .bordered;
}
.post a {
  color: red;
  .bordered;
}

As propriedades da classe .bordered agora vão aparecer tanto em #menu a como em .post a:

#menu a {
  color: #111;
  border-top: dotted 1px black;
  border-bottom: solid 2px black;
}
.post a {
  color: red;
  border-top: dotted 1px black;
  border-bottom: solid 2px black;
}

Qualquer grupo de rerga CSS do tipo classe ou id pode ser usado como mixin desta forma.

Mixins com Parâmetros

LESS possui um tipo especial de grupo de regras (ruleset) que pode ser usado como mixin, como as classes, mas que aceitam parâmetros. Este é o exemplo canônico:

.border-radius (@radius) {
  border-radius: @radius;
  -moz-border-radius: @radius;
  -webkit-border-radius: @radius;
}

E aqui como podemos usá-lo como mixin em vários grupos de regras:

#header {
  .border-radius(4px);
}
.button {
  .border-radius(6px);
}

Mixins paramétricos podem inclusive ter valores padrão para seus parâmetros:

.border-radius (@radius: 5px) {
  border-radius: @radius;
  -moz-border-radius: @radius;
  -webkit-border-radius: @radius;
}

Agora nós podemos usar o mixin anterior como:

#header {
  .border-radius;
}

E ele incluirá um border-radius de 5px.

Você pode inclusive usar mixins paramétricos que não recebem parâmetros. Isto é útil se você quiser esconder o grupo de regras da saída em CSS, mas deseja incluir as propriedades em outros grupos de regras:

.wrap () {
  text-wrap: wrap;
  white-space: pre-wrap;
  white-space: -moz-pre-wrap;
  word-wrap: break-word;
}

pre { .wrap }

Que gera a saída:

pre {
  text-wrap: wrap;
  white-space: pre-wrap;
  white-space: -moz-pre-wrap;
  word-wrap: break-word;
}

A variável @arguments

@arguments possui um significado especial dentro de mixins. Ele possui todos os argumentos passados quando o mixin foi chamado. Isto é útil se você não quer se preocupar individualmente com cada parâmetro.

.box-shadow (@x: 0, @y: 0, @blur: 1px, @color: #000) {
  box-shadow: @arguments;
  -moz-box-shadow: @arguments;
  -webkit-box-shadow: @arguments;
}
.box-shadow(2px, 5px);

O que gera a saída:

box-shadow: 2px 5px 1px #000;
-moz-box-shadow: 2px 5px 1px #000;
-webkit-box-shadow: 2px 5px 1px #000;

Pattern-matching e expressões Guard

Você pode querer modificar o comportamento de um mixin baseado nos parâmetros passados. Vamos começar com algo básico

.mixin (@s, @color) { ... }

.class {
  .mixin(@switch, #888);
}

Agora digamos que nós queremos que .mixin tenha um comportamento diferente, baseado no valor de @switch. Então poderíamos definir .mixin como:

.mixin (dark, @color) {
  color: darken(@color, 10%);
}
.mixin (light, @color) {
  color: lighten(@color, 10%);
}
.mixin (@_, @color) {
  display: block;
}

Agora, se rodarmos:

@switch: light;

.class {
  .mixin(@switch, #888);
}

Nós vamos obter o seguinte CSS:

.class {
  color: #a2a2a2;
  display: block;
}

Onde a cor passada em .mixin foi clareada. Se o valor de @switch fosse dark, o resultado teria sido uma cor escurecida.

O que aconteceu, passo-a-passo:

  • A primeira definição do mixin não se encaixava, pois era esperado o valor dark como primeiro argumento.
  • A segunda definição do mixin encaixa, pois era esperado light.
  • A terceira definição do mixin também encaixa, pois ele espera por qualquer valor.

Apenas as definições de mixins que foram encaixadas (matched) foram usadas. Variáveis encaixam e ficam vinculadas a qualquer valor. Qualquer coisa que não seja uma variável se encaixa apenas com um valor igual a si mesmo.

É possível também dar match pela aridade (número de argumentos). Aqui vai um exemplo:

.mixin (@a) {
  color: @a;
}
.mixin (@a, @b) {
  color: fade(@a, @b);
}

Agora se chamarmos .mixin com apenas um argumento, vamos ter a saída da primeira definição, mas se chamarmos .mixin com dois argumentos, o match vai acontecer na segunda definição, que pode ser traduzido para @a da um fade para @b.

Guards

Guards são úteis quando se quer dar match em expresões, e não em simples valores ou aridade. Se você é familiar com programação funcional, você provavelmente já se deparou com ela.

Na tentative de permanecer o mais próximo possível da natureza declarativa do CSS, LESS optou por implementar execução condicional através de guarded mixins ao invés de if/else, seguindo a especificação do @media query.

Vamos começar com um exemplo:

.mixin (@a) when (lightness(@a) >= 50%) {
  background-color: black;
}
.mixin (@a) when (lightness(@a) < 50%) {
  background-color: white;
}
.mixin (@a) {
  color: @a;
}

O ponto crucial aqui é a palavra reservada when, que introduz uma sequência guard (aqui com apenas um guard). Agora se rodarmos o seginte código:

.class1 { .mixin(#ddd) }
.class2 { .mixin(#555) }

Isto é o que vamos obter:

.class1 {
  background-color: black;
  color: #ddd;
}
.class2 {
  background-color: white;
  color: #555;
}

A lista completa de operadores de comparação usadas nos guards é: > >= = =< <. Adicionalmente, a palavra reservada true é o único valor verdade em uma comparação, fazendo esses dois mixins equivalentes:

.truth (@a) when (@a) { ... }
.truth (@a) when (@a = true) { ... }

Qualquer outro valor que não seja a palavra reservada true é falso em uma comparação:

.class {
  .truth(40); // N&atilde;o ir&aacute; dar match em nenhuma das defini&ccedil;&otilde;es acima.
}

Guards também pode ser separados por vírgula “,” — se algum guard for avaliado como verdadeiro, então é dado o match:

.mixin (@a) when (@a > 10), (@a < -10) { ... }

Também é possível comparar argumentos com outros argumentos, ou com não-argumentos:

@media: mobile;

.mixin (@a) when (@media = mobile) { ... }
.mixin (@a) when (@media = desktop) { ... }

.max (@a, @b) when (@a > @b) { width: @a }
.max (@a, @b) when (@a < @b) { width: @b }

E por último, se você quiser dar match em mixins baseado em valores de tipos, é possível usar as funções is*:

.mixin (@a, @b: 0) when (isnumber(@b)) { ... }
.mixin (@a, @b: black) when (iscolor(@b)) { ... }

Aqui estão as funções básicas de checagem de tipos:

  • iscolor
  • isnumber
  • isstring
  • iskeyword
  • isurl

Se você quiser checar se um valor, além de ser um número, está em uma unidade específica, você pode usar:

  • ispixel
  • ispercentage
  • isem

Além disso tudo, ainda é possível usar a palavra reservada and para condições adicionais dentro de um guard:

.mixin (@a) when (isnumber(@a)) and (@a > 0) { ... }

E a palavra reservada not para negar as condições:

.mixin (@b) when not (@b > 0) { ... }

Regras aninhadas

LESS lhe dá a habilidade de usar aninhamento, com ou sem cascateamento (cascading). Digamos que temos o seguinte CSS:

#header { color: black; }
#header .navigation {
  font-size: 12px;
}
#header .logo {
  width: 300px;
}
#header .logo:hover {
  text-decoration: none;
}

Em LESS, nós também podemos escrever da seguinte maneira:

#header {
  color: black;

  .navigation {
    font-size: 12px;
  }
  .logo {
    width: 300px;
    &:hover { text-decoration: none }
  }
}

Ou desta outra maneira:

#header        { color: black;
  .navigation  { font-size: 12px }
  .logo        { width: 300px;
    &:hover    { text-decoration: none }
  }
}

O código resultante é mais conciso, e mimica a estrutura da sua árvore DOM.

Perceba o combinador & — ele é usado quando queremos usar um seletor aninhado concatenado aos seu seletor pai, ao contrário de atuar como um descendente. Isto é muito importante para pseudo-classes como :hover e :focus.

Por exemplo:

.bordered {
  &.float {
    float: left;
  }
  .top {
    margin: 5px;
  }
}

Vai gerar a saída:

.bordered.float {
  float: left;
}
.bordered .top {
  margin: 5px;
}

Operações

Qualquer número, cor ou variável pode ser usado em operações. Alguns exemplos:

@base: 5%;
@filler: @base * 2;
@other: @base + @filler;

color: #888 / 4;
background-color: @base-color + #111;
height: 100% / 2 + @filler;

A saída é basicamente o que se espera — LESS entende a diferença entre cores e unidade. Se uma unidade é usada em uma operação, como em:

@var: 1px + 5;

LESS irá usar esta unidade para a saída final — 6px neste caso.

Parênteses também são permitidos nessas operações:

width: (@var + 5) * 2;

E são obrigatórios em valores compostos:

border: (@width * 2) solid black;

Funções de cor

LESS fornece uma variedade de funções que transformam cores. Cores são primeiramente convertidas para o formato HSL, e então manipuladas a nível de canal:

lighten(@color, 10%);     // retorna uma cor que &eacute; 10% *mais clara* que @color
darken(@color, 10%);      // retorna uma cor que &eacute; 10% *mais escura* que @color

saturate(@color, 10%);    // retorna uma cor 10% *mais* saturada que @color
desaturate(@color, 10%);  // retorna uma cor 10% *menos* saturada que @color

fadein(@color, 10%);      // retorna uma cor 10% *mais* transparente que @color
fadeout(@color, 10%);     // retorna uma cor 10% *more* transparente que @color
fade(@color, 50%);        // retorna @color com 50% de transparencia

spin(@color, 10);         // retorna uma cor com uma matiz (hue) 10 graus maior que @color
spin(@color, -10);        // retorna uma cor com uma matiz (hue) 10 graus menor que @color

mix(@color1, @color2);    // retorna uma mistura entre a @color1 e @color2

O uso das funções é bem simples:

@base: #f04615;

.class {
  color: saturate(@base, 5%);
  background-color: lighten(spin(@base, 8), 25%);
}

Também é possível extrair informação das cores:

hue(@color);        // retorna o canal `matiz` (hue) de @color
saturation(@color); // retorna o canal `satura&ccedil;&atilde;o` (saturation) de @color
lightness(@color);  // retorna o canal `luminosidade` (lightness) de @color
alpha(@color);      // retorna o canal "alpha" de @color

Isto é útil se quisermos criar uma nova cor baseada em um canal de uma outra cor, por exemplo:

@new: hsl(hue(@old), 45%, 90%);

@new vai ter o hue de @old, e sua própria saturation e lightness.

Funções Matemáticas

LESS fornece algumas funções matemáticas bastante úteis que podemos usar com valores:

round(1.67); // retorna `2`
ceil(2.4);   // retorna `3`
floor(2.6);  // retorna `2`

Se precisarmos transformar um valor em uma porcentagem, podemos fazer isso com a função percentage:

percentage(0.5); // retorna `50%`

Namespaces

Algumas vezes, queremos agrupar nossas variáveis e mixins, por motivos de organização, ou apenas para oferecer encapsulamento. Podemos fazer isso de forma intuitiva em LESS — digamos que queremos criar um pacote com alguns mixins e variáveis com o nome #bundle, para reuso posterior ou para distribuição:

#bundle {
  .button () {
    display: block;
    border: 1px solid black;
    background-color: grey;
    &:hover { background-color: white }
  }
  .tab { ... }
  .citation { ... }
}

Agora se quisermos adicionar o classe .button do mixin ao nosso #header a, podemos fazer da seguinte forma:

#header a {
  color: orange;
  #bundle > .button;
}

Escopo

Escopo em LESS é muito semelhante aos de linguagens de programação. Variáveis e mixins são primeiramente procurados localmente, e caso não sejam encontrados, o compilador irá procurar no escopo pai, e assim por diante.

@var: red;

#page {
  @var: white;
  #header {
    color: @var; // white
  }
}

#footer {
  color: @var; // red
}

Comentários

Comentários seguindo o padrão CSS são preservados em LESS:

/* Ol&aacute;, sou um coment&aacute;rio no estilo CSS */
.class { color: black }

Comentário de uma linha também são válidos no LESS, mas são “silenciosos”, eles não aparecem no CSS compilado:

// Opa, sou um coment&aacute;rio do tipo silencioso e n&atilde;o vou aparecer no CSS final
.class { color: white }

Importação

Podemos também importar arquivos .less, e todas as variáveis e mixins incluídos nestes arquivos estarão disponíveis no arquivo principal. A extensão .less é opcional, então ambas as regras são válidas:

@import 'lib.less';
@import 'lib';

Se quisermos importar um arquivo CSS, e não quisermos que LESS processe ele, apenas usamos a extensão .css:

@import 'lib.css';

A diretiva ficará como está, e acabará como uma saída CSS.

Interpolação de strings

Variáveis podem ser incluídas dentro de strings de uma maneira similar a ruby ou PHP, com o construtor @{name}

@base-url: 'http://assets.fnord.com';
background-image: url('@{base-url}/images/bg.png');

Escaping

Podemos precisar usar um valor CSS na saída que não é válido pela sintaxe do CSS, ou utiliza uma sintaxe proprietária que LESS não reconhece.

Para gerar a saída de tal valor, o colocamos dentro de uma string começando com ~, por exemplo:

.class {
  filter: ~'ms:alwaysHasItsOwnSyntax.For.Stuff()';
}

Isto é chamado de ‘escaped value’, que irá resultar em:

.class {
  filter: ms:alwaysHasItsOwnSyntax.For.Stuff();
}

Avaliação (evaluation) de JavaScript

Expressões JavaScript podem ser avaliadas (evaluate) como valores dentro dos arquivos .less. Isto é feito colocando a expressões entre crases:

@var: `'hello'.toUpperCase() + "!"`;

Gera a saída:

@var: 'HELLO!';

Também é possível usar interpolação e escaping com as strings:

@str: 'hello';
@var: ~`'@{str}'.toUpperCase() + "!"`;

Gera a saída:

@var: HELLO!;

É possível inclusive acessar o ambiente JavaScript:

@height: `document.body.clientHeight`;

Se quisermos dar um parse em uma string JavaScript como uma cor hexadecimal, podemos utilizar a função color:

@color: color(`window.colors.baseColor`);
@darkcolor: darken(@color, 10%);

Sobre

LESS foi desenvolvido por Alexis Sellier, mais conhecido como cloudhead.

Traduzido para o português por Loop Infinito (@loopinfinito).

powered by LESS

Copyright © Alexis Sellier 2010-2012

Fork me on GitHub