Interpolando variáveis com Sass (Sass interpolation)

Neste artigo vamos analisar como funciona a interpolação de variáveis na linguagem Sass, com base em simples casos de uso.

Então você curte utilizar o pré processador Sass. Ela de fato otimiza sua produtividade. Mas ainda existe uma coisa que você não consegue entender: interpolação (ou interpolation, em inglês) – que basicamente significa encaixar valores dentro de outros valores. Hoje você está com sorte, pois neste artigo vamos abordar como funciona a interpolação no Sass.

Este post faz parte do projeto que participo de tradução dos artigos dos blogs da Envato, Webdesigntuts+, Gamedevelopmenttuts+ e Nettuts+.

Link para artigo original: All You Ever Need to Know About Sass Interpolation
Autor do artigo original: Hugo Giraudel
Link da Envato para o artigo traduzido: Tudo Que Você Sempre Quis Saber Sobre Interpolação no Sass

Interpo… o que?

Interpolar ou interpolation, as vezes mencionada como variable interpolation/interpolação de variáveis não é uma funcionalidade exclusiva do Sass. Atualmente você encontra essa funcionalidade em diversas linguagens (PHP, Perl, Ruby, Tcl, Groovy, Unix shells…). As vezes também comentamos sobre interpolar uma variável/interpolating a variable ou interpolar uma expressão/interpolating an expression. Sem mais delongas, interpolar é o processo de analisar uma expressão ou uma string com uma ou mais variáveis, gerando um resultado onde as variáveis são substituídas pelos valores presentes em memória.

Hmm.

Vamos analisar um exemplo. Se você tem conhecimento básico em PHP você vai conseguir entender este exemplo. Digamos que você quer apresentar uma string que contém uma variável. A maneira mais comum para fazer isso é esta:

$description = "awesome";
echo "Tuts+ is " . $description . "!";

Isso não é interpolar. Isso na verdade é o método de concatenar strings/string-concatenation. Estamos concatenando (juntando) três strings: "Tuts+ is ","awesome" (como $description) e "!". Podemos interpolar, ao invés de concatenar uma string, veja o exemplo:

$description = "awesome";
echo "Tuts+ is ${description}!";

As chaves em volta da variável orientam o PHP a printar o valor da variável junto a string. Note que precisamos utilizar aspas duplas para este recurso com a linguagem PHP (e para maioria das linguagens).

De qualquer forma, isso é uma interpolação de expressão/variável. Utilizar tanto interpolação quando concatenação é uma decisão sua, mas digamos que a interpolação é uma maneira mais fácil de ler e entender a concatenação de strings.

Interpolando variáveis na linguagem Sass - Web Social Dev
Legal.

E o Sass?

Vamos analisar como a substituição de variável ocorre utilizando o pré processador Sass.

As variáveis da linguagem Sass, assim como no PHP, utilizam o símbolo do dólar $ para indicar uma variável. Pois é ai também que a diferenteça termina, o Sass tem uma abordagem totalmente diferente para interpolação. E existe uma razão para isso: Sass opera sobre a linguagem Ruby, que utiliza #{} para substituir expressões.

Exemplo, utilizando Sass:

$description: "awesome";
@warn "Tuts+ is #{$description}!";
Interpolando variáveis na linguagem Sass - Web Social Dev

Note que o símbolo $ é utilizado para indicar a variável, ao contrário do PHP. A variável é apenas declarada entre #{}. Vale salientar que você pode interpolar qualquer tipo de variável, além de strings. Por exemplo:

$answer: 42;
@warn "The Answer to the Ultimate Question of Life, the Universe, and Everything is #{$answer}.";

Quando eu devo utilizar a interpolação?

Agora que você sabe o que é interpolar uma variável e como utilizar com Sass, é hora de analisar alguns casos de uso. Para a primeira análise, vamos utilizar o exemplo da diretiva <a href="http://sass-lang.com/documentation/file.SASS_REFERENCE.html#_6" target="_self">@warn</a>, para printar o conteúdo no console.

Strings

Digamos que você tem um map/mapa de cores chamado $colors (map é uma variável que contém um série de valores) e que você está cansado de digitar <a href="http://sass-lang.com/documentation/Sass/Script/Functions.html#map_get-instance_method" target="_self">map-get($colors, ...)</a> a todo momento, então você cria uma função color() que aponta a cor mapeada para qualquer valor apresentado. Vamos escrever o código básico juntos:

// _config.scss
$colors: (
  "primary": tomato,
  "secondary": hotpink
);

// _function.scss
@function color($key) {
  @return map-get($colors, $key);
}

// _component.scss
.el {
  background-color: color(primary);
}


Digamos que agora você quer ser informado quando um valor não existe ou quando é apresentado um valor desconhecido para o mapa (by the way, este artigo pode interessar introduction to error handling in Sass.) Isso pode ser feito com a diretiva @warn na função color().

@function color($key) {
  @if not map-has-key($colors, $key) {
    @warn "Key not found.";
  }
  @return map-get($colors, $key);
}

E se você quiser indentificar qual valor não foi encontrado?

@function color($key) {
  @if not map-has-key($colors, $key) {
    @warn "Key `#{$key}` not found.";
  }
  @return map-get($colors, $key);
}

Pronto, você interpolou as variáveis. Requisitar color(awesomeness) vai apresentar a seguinte mensagem no console:

Key awesomeness not found.

Bacana, mas o contexto ficou um pouco obscuro. Para ajudar, podemos incluir o nome do map junto a mensagem de erro.

@function color($key) {
  @if not map-has-key($colors, $key) {
    @warn "Key `#{$key}` not found in $colors map.";
  }
  @return map-get($colors, $key);
}

Assim, mesmo a variável $colors não sendo interpolada ela vai se apresentar como uma string.

Key awesomeness not found in $colors map.

Funções CSS

Até agora, vimos o caso mais comum de substituição de variáveis: printar o conteúdo de uma variávem em uma string. Esse exemplo é muito bom, mas existem exemplos mais interessantes: variáveis em funções CSS, por exemplo calc().

Digamos que você quer ajustar o tamnho do seu container se baseando na largura da sidebar. Com o valor da largura da sidebar guardado em uma variável, podemos seguir este exemplo:

$sidebar-width: 250px;

.main {
  width: calc(100% - $sidebar-width);
}

Surpresa! Não funcionou. O Sass não apresentou erro, e o container não foi ajustado esperado. Se você analisar os estilos com o DevTools, você vai ver o estilo riscado – que significa que é uma propriedade inválidade não aplicada:

.main {
  width: calc(100% - $sidebar-width);
}

Vamos pensar sobre isso: calc() é uma função CSS, não uma função Sass. Isso significa que o Sass interpreta toda a expressão em uma string. Teste este exemplo:

$type-of-expression: type-of(calc(100% - $sidebar-width)); // string

Por ser uma string, não há razão para o Sass agir diferente como o caso da variável $colors na string @warn. Mas não é isso que você espera, certo? Vamos interpolar isso!

.main {
  width: calc(100% - #{$sidebar-width});
}

Agora, quando o Sass compilar os estilos, ele vai substituir o código #{$sidebar-width} pelo valor associado a $sidebar-width, neste caso 250px, resultando na expressão CSS:

.main {
  width: calc(100% - 250px);
}


Missão cumprida! Neste exemplo utilizamos a função calc() mas é a mesma coisa para outras funções como url(), linear-gradient(),radial-gradient(), cubic-bezier() e qualquer outra função nativa do CSS, incluindo pseudo-classes.

Outro exemplo utilizando funções CSS:

@for $i from 1 through $max {
  .el:nth-of-type(#{$i}) {
    // ...
  }
}

Esse é um caso que você ja deve ter se deparado: utilizar o looping for com os seletores :nth-*(). Mais uma vez, você vai precisar interpolar a variável para que ela seja apresentada no CSS gerado.

Para fixar: a linguagem Sass trata as funções CSS como string, fazendo com que você evite o uso de qualquer variável utilizada pois o valor da mesma será apresentado no CSS gerado.

Diretivas CSS

Seguindo em frente, temos outro exemplo interessante de interpolação: diretivas CSS, como por exemplo @support, @page e @media.

Este tem mais a ver com a forma que o Sass analisa o CSS perante as diretivas, espcialmente a diretiva de mídia. Analisando o código Sass, já que minha experiência em Ruby não é lá essas coisas, eu encontrei algo interessante:

def query_expr
    interp = interpolation
    return interp if interp
    return unless tok(/(/)
    res = ['(']
    ss
    res &lt;&lt; sass_script(:parse)

    if tok(/:/)
      res &lt;&lt; ': '
      ss
      res &lt;&lt; sass_script(:parse)
    end
    res &lt;&lt; tok!(/)/)
    ss
    res
  end

Basicamente, as primeiras linhas orientam o Sass a retornar o media query caso haja expressão interpolada, ou erro, a não ser que seja detectada a presença do parênteses ((), caso contrário ele deve continuar a verificação até o fim. Vamos analisar um exemplo:

$value: screen;

@media $value {
  // ...
}


Como esperado, o exemplo apresenta falha:

Invalid CSS after “@media “: expected media query (e.g. print, screen, print and screen), was “$value {“

Segundo a mensagem de erro, o Sass espera uma media query. Neste momento, você precisa interpolar sua variável se ela é apresentada depois da string @media. Por exemplo:

$value: screen;

@media #{$value} {
  // ...
}

Como verificado acima na breve análise da linguagem Ruby, se a @media é seguida de parênteses (()), você não precisa interpolar a variável, porque o Sass vai considerar qualquer coisa dentro do parenteses. Por exemplo:

$value: 1336px;

@media (max-width: $value) {
  // ...
}

Neste caso, o Sass avalia a expressão (max-width: $value), que se transforma em (max-width: 1337px), gerando um CSS válido sem a necessidade de alterar a variável.

Perguntei ao Nathan Weizenbaum, porque o Sass é mantido desta forma e obtive a seguinte resposta:

Em geral, não orientamos que variáveis X sejam utilizadas onde espressões SassScript não podem ser utilizadas. Media queries são uma solução, tendo em mente a ambiguidade do SassScript (em maps especialmente).

In general, we don’t like allowing raw variables in places where full SassScript expressions can’t be used. Media queries are such a place, since SassScript can be ambiguous there (maps especially).

— Nathan Weizenbaum (@nex3) June 10, 2014

Seletores

Este é o ultimo caso de uso, onde vamos interpolar variáveis Sass: quando utilizar uma variável como seletor ou parte dele. Apesar de não ser um caso presente no dia dia, é comum se deparar com algo como:

$value: custom;

selector-$value {
  property: value;
}

Infelizmente, este recurso não funciona, apresentando a falha:

Invalid CSS after “selector-“: expected “{“, was “$value {“

A falha é apresentada basicamento pelo menos motivo do exemplo com media query. O Sass tem sua própria maneira de interpretar seletores CSS. Se ele encontra algo inesperado, neste caso o sinal do dólar (que indica a variável), ele apresenta erro.

Felizmente, solucionar essa falha é fácil (agora que você já conhece a solução): basta interpolar a variável.

$value: custom;

selector-#{$value} {
  property: value;
}


Conclusão

No final, interpolar na linguagem Sass não é tão simples quanto parecia. Vão existir casos onde você vai precisar utilizar ou não as variáveis.

Espero que vocês tenham entendido como a interpolação funciona na linguagem Sass, qualquer informação adicional é bem vinda nos comentários.