Cutting Edge

Programação em CSS: Faça mais com o 'LESS'

Dino Esposito

Dino EspositoNeste artigo, discutirei o desenvolvimento da Web usando o LESS Framework para geração dinâmica de conteúdo CSS.

Com certeza, o CSS representou um grande avanço com sua promessa, grandemente atendida, de separar completamente o conteúdo da apresentação de páginas da Web. Embora o CSS esteja (ou deveria estar?) no território dos designers, ele anuncia o princípio de separação de problemas, com o qual quase todo desenvolvedor se preocupa. Portanto, o uso do CSS foi adotado rapidamente e se tornou profundamente arraigado no desenvolvimento da Web até um ponto onde ele precisa lutar algumas vezes para acompanhar os sites modernos.

O ponto não é que o CSS seja insuficiente para aplicar estilo a sites modernos, ricos em gráficos e atraentes, mas sim uma linguagem puramente declarativa que nem sempre é apropriada para expressar declarações complexas e interconectadas de estilos. Felizmente, os navegadores ainda podem compreender qualquer CSS desde que ele seja escrito corretamente, mas podemos dizer o mesmo em relação a pessoas?

Uma direção relativamente nova no desenvolvimento da Web visa a criar uma infraestrutura em torno do CSS para que os desenvolvedores e designers possam gerar o mesmo CSS de uma maneira mais sustentável. A folha de estilos final para o navegador não é alterada, mas a maneira como ela é gerada deve ser diferente, mais fácil de ler e mais gerenciável.

Esse campo do desenvolvimento da Web começou há alguns anos e agora está atingindo a maturidade, uma vez que várias estruturas disponíveis podem ajudar você com geração dinâmica de conteúdo CSS. Fornecerei um resumo executivo de uma dessas estruturas, a LESS Framework, e mostrarei como ela pode ser integrada com as soluções ASP.NET MVC.

Por que o LESS?

Um dos maiores problemas que os desenvolvedores resolvem com o LESS é a repetição de informações. Como desenvolvedor de software, você provavelmente conhece o princípio de DRY (“não se repetir”) e o aplica diariamente. O maior benefício do DRY é que isso reduz os lugares onde são armazenadas as mesmas informações e, portanto, o número de lugares onde elas devem ser atualizadas.

No CSS básico, você simplesmente não tem problemas de DRY. Por exemplo, em alguns outros cenários, se uma cor for usada em várias classes e você precisar alterá-la, você provavelmente não terá uma alternativa melhor do que atualizá-la em cada ocorrência individual. As classes CSS permitem definir a aparência de determinados elementos e utilizá-los entre páginas para aplicar o estilo relacionado aos elementos da mesma maneira. Embora as classes CSS realmente reduzam a repetição, algumas vezes elas não são suficientes em outros aspectos.

Um problema com as classes CSS é que elas funcionam no nível do elemento HTML semântico. Ao criar várias classes CSS, você sempre enfrenta a repetição de pequenos fragmentos de informações, como cores ou larguras. Você não pode facilmente ter uma classe para cada um desses pequenos fragmentos repetíveis. Mesmo que você consiga ter uma classe CSS para quase qualquer estilo repetível, como cores e larguras, ao aplicar estilo a elementos semânticos, digamos, um contêiner, você deve concatenar várias classes CSS em conjunto para obter o efeito desejado.

Se você já tiver usado uma estrutura, como Bootstrap, para criar sua página da Web, você sabe o que quero dizer. Veja um exemplo:

<a class="btn btn-primary" ... />

Primeiro a âncora é definida como um botão (classe btn) e, em seguida, um tipo específico de botão (classe btn-primary). Essa abordagem funciona, mas pode exigir esforço significativo para o planejamento antecipado das classes das quais você precisa. Isso resulta em sobrecarga em projetos da Web que estão sempre à beira do prazo final.

Uma linguagem de folha de estilo dinâmica, como o LESS, representa um espécie de raciocínio lateral. Você não gasta nenhum tempo tentando tornar seu CSS básico mais inteligente, você simplesmente usa ferramentas diferentes, principalmente linguagens, para gerá-las. Portanto, o LESS é uma estrutura que adiciona conceitos amigáveis ao programador para a codificação CSS, como variáveis, blocos e funções.

O problema de processá-lo para CSS básico para consumo do navegador está estritamente relacionado à geração de CSS dinâmico. O cliente pode processar o código do LESS por meio de código JavaScript ad hoc ou reprocessá-lo no servidor para que o navegador receba apenas o CSS final.

Configurando o LESS no ASP.NET MVC

Demonstrarei o que é necessário para usar o LESS dentro de um aplicativo ASP.NET MVC. Para começar, focalizarei o processamento no lado do cliente do código LESS. Na seção HEAD do arquivo de layout, adicione o seguinte:

<link rel="stylesheet/less"
  type="text/css"
 href="@Url.Content("~/content/less/mysite.less")" />
<script type="text/javascript"
 src="@Url.Content("~/content/scripts/less-1.3.3.min.js")"></script>

Isso assume que você criou uma pasta Content/Less no projeto para conter todos os seus arquivos LESS. Você precisará de um arquivo JavaScript para o processamento real de LESS para CSS dentro do navegador. Você pode obter o arquivo script no lesscss.org. Reverei alguns cenários onde o LESS prova ser útil.

LESS em Ação: variáveis

Uma boa maneira de compreender a função das variáveis do LESS é examinar os gradientes do CSS. Por anos, os designers usaram arquivos GIF pequenos para pintar o plano de fundo de contêineres HTML com gradientes. Mais recentemente, os navegadores adicionaram suporte ao CSS para gradientes. Esses também fazem parte do padrão oficial do CSS3 por meio da sintaxe gradiente linear e suas variações. Infelizmente, se você desejar ter certeza de que o gradiente seja escolhido pelo maior intervalo possível de navegadores, você precisará recorrer a algo parecido com o código da Figura 1.

O código da Figura 1 é quase ilegível. O pior é que ele precisa ser repetido em qualquer lugar em que você deseje aquele gradiente. Além disso, se você desejar alterar a cor do gradiente levemente (ou simplesmente a saturação ou o esmaecimento), a única opção será editar todas as ocorrências manualmente. Para ir direto ao ponto, isso pode ser extremamente difícil. No entanto, essa é a única maneira como isso pode funcionar no CSS básico.

Figura 1 Código abrangente para exibir gradientes em um grande intervalo de navegadores

/* Old browsers fallback */
background-color: #ff0000;
background: url(images/red_gradient.png);
background-repeat: repeat-x;
/* Browser specific syntax */
background: -moz-linear-gradient(  left,  #fceabb 0%, 
  #fccd4d 50%, #f8b500 51%, #fbdf93 100%);
background: -Webkit-linear-gradient(  left, #fceabb 0%,
  #fccd4d 50%,#f8b500 51%,#fbdf93 100%);
background: -o-linear-gradient(  left, #fceabb 0%,
  #fccd4d 50%,#f8b500 51%,#fbdf93 100%);
background: -ms-linear-gradient(  left, #fceabb 0%,
  #fccd4d 50%,#f8b500 51%,#fbdf93 100%);
/* Standard syntax */
background: linear-gradient(  to right, #fceabb 0%,
  #fccd4d 50%,#f8b500 51%,#fbdf93 100%);

Para encontrar uma solução melhor, você precisa olhar fora do CSS e entrar no território do LESS. No LESS, você define o CSS para o gradiente uma vez e faz referência a ele por nome sempre que necessário. Veja um exemplo:

.background-gradient-orange { background: #fceabb; ... }
.container { .background-gradient-orange; }

A classe denominada background-gradient-orange é inserida pelo nome no contêiner de classes e em qualquer outra classe quando necessário. A definição do gradiente, no entanto, é mantida em um único lugar.

Não há nada de revolucionário nisso, se você olhar de uma perspectiva de desenvolvedor. No entanto, ele usa um recurso, variáveis, que simplesmente não existe no CSS. A sintaxe anterior, na verdade, não funcionará se você salvar e fizer referência ao arquivo como uma folha de estilos sem formatação. Algum código é necessário para tornar a sintaxe estendida em CSS básico. O analisador de JavaScript do LESS faz exatamente isso e expande as variáveis para seu conteúdo CSS real.

As variáveis também se aplicam a valores escalares, como cores e tamanhos. Considere o código LESS a seguir:

@black: #111;
#main {  color: @black; }
.header { background-color: @black; }

O analisador expande a variável @black para o valor atribuído e a substitui em todo o arquivo. O efeito líquido é que você altera a cor real em um lugar e altera a ondulação pelo arquivo automaticamente.

LESS em Ação: importações

Você pode dividir seu código LESS em vários arquivos, arquivos de referência e classes independentes onde necessário. Por exemplo, suponha que você crie um arquivo gradients.less com o seguinte conteúdo:

.background-gradient-orange { background: #fceabb; ... }

Em outro arquivo LESS, digamos main.less, você pode fazer referência a quaisquer gradientes importando o arquivo:

@import "gradients";
.container { .background-gradient-orange; }

Se o gradients.less (a rigor a extensão não é necessária) residir em outra pasta, você deverá indicar as informações do caminho na chamada de import.

Mesclas do LESS

Eu chamei o artefato LESS para gradientes de uma variável. Para ser preciso, isso não está totalmente correto. No LESS, uma variável engloba um único valor. Um contêiner para uma classe CSS é conhecido como uma mescla. É semelhante a uma função, mas não contém nenhuma lógica personalizada. Assim como uma função, uma mescla do LESS pode utilizar e processar parâmetros. Considere o código na Figura 2 que demonstra uma mescla.

Na Figura 2, uma mescla denominada shadow define os estilos de uma sombra de caixa e expõe a cor como um parâmetro externo. De maneira semelhante, a mescla da caixa de texto define a aparência básica de um campo de entrada. Importa a definição da sombra e mantém a largura paramétrica. Dessa maneira, a definição de três classes para campo de entrada de tamanhos diferentes (mini, normal e grande) é muito simples. O mais importante é que isso requer uma fração da edição e precisa de muito pouco esforço para atualização (consulte a Figura 3).

Figura 2 Mesclas no LESS Framework

/*  Mixins  */
.shadow(@color) {
  box-shadow: 3px 3px 2px @color;
}
.text-box(@width) {
  .shadow(#555);
  border: solid 1px #000;
  background-color: #dddd00;
  padding: 2px;
  width: @width;
}
/*  CSS classes  */
.text-box-mini {
  .text-box(50px);
}
.text-box-normal {
  .text-box(100px);
}
.text-box-large {
  .text-box(200px);
}

LESS Mixins in Action
Figura 3 Mesclas do LESS em ação

As mesclas podem aceitar vários parâmetros e também um número variável de parâmetros. Além disso, parâmetros individuais dão suporte a valores padrão:

.mixin(@color: #ff0) { ... }

O LESS não é uma expressão de uma linguagem de programação sofisticada e, por design, não tem comandos para indicar condições ou loops. No entanto, o comportamento de uma mescla ainda pode ser diferente dependendo do valor passado. Suponha que você queira que um botão tenha uma borda e uma fonte mais espessas. Você define uma mescla paramétrica denominada button e usa a palavra-chave “when” para associar as definições a uma condição. A condição deve ser baseada em um único parâmetro:

.button (@size) when (@size < 100px) {
 padding: 3px;
 font-size: 0.7em;
 width: @size *2;
}
.button (@size) when (@size >= 100px) {
  padding: 10px;
  font-size: 1.0em;
  font-weight: 700;
  background-color: red;
  width: @size *3;
}

Você aplica diferentes configurações, mas também pode usar operações básicas para multiplicar o tamanho por um fator. Em seguida, use mesclas em classes CSS reais:

.push-button-large {
  .button(150px);
}
.push-button-small {
  .button(80px);
}

Os resultados da execução desse código são mostrados na Figura 4.

Effects of Using LESS Mixins in CSS Classes
Figura 4 Efeitos do uso de mesclas LESS em classes CSS

O LESS é fornecido com uma longa lista de funções predefinidas para manipulação de cores. Você tem funções para escurecer, clarear e saturar cores por uma porcentagem e para aplicar fade-in e fade-out por uma porcentagem, conforme mostrado aqui:

.push-button {
  background-color: fade(red, 30%);
}

Para obter a documentação completa sobre as funções que têm suporte do LESS, verifique o lesscss.org.

Aninhando classes

Pessoalmente, considero um aborrecimento precisar repetir blocos CSS para indicar estilos irmãos. Um exemplo típico é:

#container h1 { ... }
#container p { ... }
#container p a { ... }
#container img { ... }

Em CSS básico bem-escrito, você pode realmente evitar muita repetição, mas a maneira como os estilos são apresentados, usando uma lista plana, não é a ideal. Nesse caso, um pouco de hierarquia é preferível. No LESS, você pode aninhar regras de estilo como esta:

.container {
  h1 {
    font-size: 0.8em;
   color: fade(#333, 30%);
   a {
     color: #345;
     &:hover {color: red;}
    }
  }
}

Uma vez processado, o código LESS anterior produz os seguintes estilos:

.container h1
.container h1 a
.container h1a:hover

Processamento no lado do servidor

Você pode baixar o código LESS da maneira como se encontra e processá-lo no cliente por meio de código JavaScript. Você também pode pré-processar no servidor e baixá-lo no cliente como um CSS básico. No caso anterior, tudo funciona como se você estivesse usando arquivos CSS básicos: Alterações no lado do servidor são aplicadas ao cliente com a próxima atualização da página.

O pré-processamento no lado do servidor poderá ser uma opção melhor se você tiver problemas de desempenho e estiver lidando com arquivos CSS grandes e complexos. O pré-processamento no lado do servidor ocorre sempre que você modifica o CSS no servidor. Você pode cuidar manualmente da etapa extra no final do processo de compilação. Você pré-processa o código LESS para o CSS usando o compilador LESS na linha de comando. O compilador faz parte do pacote NuGet da dotless que você instala para trabalhar no lado do servidor.

No ASP.NET MVC 4, no entanto, você pode integrar o LESS Framework com o mecanismo de agrupamento coberto em minha coluna de outubro de 2013, “Programação em CSS: agrupamento e minificação” (msdn.microsoft.com/magazine/dn451436). Isso garante que a transformação do LESS para o CSS seja executada sempre que você fizer uma solicitação para um arquivo LESS. Também garante que o cache seja gerenciado de maneira apropriada por meio do cabeçalho If-Modified-Since. Finalmente, você pode mesclar a análise e a minificação. Para integrar o LESS no ASP.NET MVC, primeiro baixe e instale o pacote NuGet da dotless. Em seguida, adicione o código a seguir à classe BundleConfig:

var lessBundle =
  new Bundle("~/myless").IncludeDirectory("~/content/less", "*.less");
lessBundle.Transforms.Add(new LessTransform());
lessBundle.Transforms.Add(new CssMinify());
bundles.Add(lessBundle);

O agrupamento empacotará todos os arquivos .less encontrados na pasta especificada. A classe LessTransform é responsável pela transformação do LESS para CSS. A classe usa a API da dotless para analisar scripts LESS. O código de LessTransform é bem simples:

public class LessTransform : IBundleTransform
{
  public void Process(BundleContext context, BundleResponse response)
  {
    response.Content = dotless.Core.Less.Parse(response.Content);
    response.ContentType = "text/css";
  }
}

Ferramentas mais inteligentes

O LESS não é o único pré-processador do CSS por aí. O Syntactically Awesome Stylesheets (Sass) é outro pré-processador popular (sass-lang.com), para citar apenas um exemplo. A conclusão é que, independentemente da ferramenta, um pré-processador do CSS é definitivamente algo que você desejará considerar para programação extensiva da Web Quer você seja um designer gráfico ou um desenvolvedor, ferramentas mais inteligentes para gerenciar e organizar o código CSS são quase uma necessidade. São ainda melhores quando são integradas na plataforma da Web. Finalmente, observe que o Visual Studio 2012 e o Visual Studio 2013 oferecem excelente suporte para o LESS (e as tecnologias relacionadas) por meio da extensão do Web Essentials, que você pode baixar em vswebessentials.com. Além disso, o editor do LESS está disponível no Visual Studio 2012 Update 2 e no futuro Visual Studio 2013.

Dino Esposito é o autor de “Architecting Mobile Solutions for the Enterprise” (Microsoft Press, 2012) e de “Programming ASP.NET MVC 5”, que será lançado em breve pela Microsoft Press. Divulgador técnico das plataformas .NET e Android no JetBrains e palestrante frequente em eventos do setor no mundo todo, Esposito compartilha sua visão de software em software2cents.wordpress.com e no Twitter, em twitter.com/despos.

Agradecemos ao seguinte especialista técnico pela revisão deste artigo: Mads Kristensen (Microsoft)
Mads Kristensen é gerente de programa na equipe de Plataformas e ferramentas da Web na Microsoft, que trabalha com experiências de desenvolvedor da Web do Visual Studio. Tem mais de uma década de experiência em desenvolvimento de aplicativos Web na plataforma Microsoft. Fundou o projeto de software livre BlogEngine.NET que se tornou o aplicativo de blog mais popular na plataforma do ASP.NET, usado por 800.000 pessoas do mundo inteiro. Kristensen também é o criador de algumas extensões populares do Visual Studio, incluindo o Web Essentials, o Image Optimizer e o CssCop.