3 coisas que você poderia estar fazendo com Sass e talvez não esteja

Muito além do CSS aninhado

A Syntactically Awesome Style Sheets, ou Sass, se define por ela mesma um “CSS com superpoderes”, mas basicamente o que todo mundo pensa quando falamos sobre ela é o CSS aninhado. Entretanto, podemos ir muito além disso, usando a Sass para códigos mais enxutos, menos repetitivos e mais legíveis. Quer saber como? Neste post vou falar sobre três recursos incríveis que podem te ajudar muito no dia-a-dia. Vamos lá?

1. Código BEM aninhado

Geralmente, as pessoas optam por Sass pela possibilidade de escrever CSS de maneira aninhada:

.element {
/*...*/
.children {
/*...*/
&:hover {
/*...*/
}
}
}

Porém, algumas pessoas ainda não utilizam o parent selector (&), que simboliza a classe CSS pai do elemento em que ela está dentro:

.element {
&__modal {
/* é compilado para .element__modal */
}
}

E isso é muito útil principalmente quando seguimos um padrão de CSS como o BEM (Block — Element — Modifier), que algumas pessoas reclamam que possuem classes com nomes muito extensos. Com o Sass, conseguimos quebrar a escrita deste código logicamente usando parent selector:

.block {
&__element {
/* compila pra .modal__container*/
&--modifier {
/* compila pra .modal__container--open*/
}
}
}

Quanto mais é respeitada a estrutura de blocos, elementos e modificadores, menor a necessidade de aninhar mais de três elementos, o que chamamos de overstacking e dificulta a legibilidade do código.

Outra maneira de evitar aninhamento excessivo de código é pensar que não é só porque elementos estão dentro de um mesmo bloco que eles não podem ser tratados como blocos diferentes. Se dentro de um <nav> você tem um item que é um dropdown complexo e cheio de etapas, ao invés de escrevê-lo inteiro dentro do nav, você pode tratá-lo como um bloco à parte. Um exemplo são arquiteturas como CubeCSS, que possuem maneiras de evitar depositar estruturas muito grandes em blocos com suas globals, layouts e utilitários. Vale a pena dar uma olhada.

2. Loops e Mapas

Imagina que você tem um componente de botão que tem diversas variantes. Geralmente a galera resolve esse problema na unha escrevendo classe por classe ou, se tiver usando algum framework de Javascript, passando cada uma das propriedades CSS como props, o que é crime em 17 países segundo a ONU. Os maps e loops do Sass podem te ajudar a gerar todas essas variantes sem o trabalho braçal de escrever todas elas, dados os seguintes requisitos:

  • Não é recomendado que suas variantes sejam muito diferentes, mas que pelo menos possuam boa parte das propriedades em comum.
  • Suas variantes não podem ser editáveis via interface, pra esse fim é recomendado utilizar outra estratégia como classes utilitárias ou CSS-in-JS, que eu particularmente não gosto, mas eu tenho amigues que gostam.

Primeiro passo: agrupe suas variáveis
Vamos supor que o que varia entre esses botões é apenas a cor e a opacidade quando é :disabled, vamos usar as cores do bootstrap de exemplo. A primeira coisa a se fazer é criar um mapa com o nome da cor, a cor e a cor da fonte:

// variáveis de cor
$white: #FCFAF7;
$lightgrey: #D5D5D5;
$mediumgrey: #B1B1B1;
$darkgrey: #505155;
$primary: #34CED1;
$success: #7DCC3D;
$danger: #E64545;
$warning: #ffc107;

// Mapa de cores do botão
$buttons-map:
"primary" $primary $white,
"danger" $danger $white,
"success" $success $white,
"warning" $warning $darkgrey,
"dark" $darkgrey $white,
"secondary" $mediumgrey $white;

A sintaxe do map é bem flexível, nesse caso, cada vírgula separa uma lista com três itens, como se fosse uma array. É possível também criar uma chave: valor como em objetos da seguinte forma:

$font-map: (
"heading-1": ($ft-poppins, 2.9rem, bold),
"heading-2": ($ft-poppins, 1.8rem, bold),
"subheading": ($ft-poppins, 1.375rem, 200),
"title": ($ft-noto, 1.05rem, bold),
"text": ($ft-noto, 1rem, 200),
"text-small": ($ft-noto, 0.75rem, 200)
);

Se você usa Javascript, esse map é basicamente isso aqui:

let font-map = {
"heading-1": { ft-poppins, '2.9rem', 'bold },
// ...
}

Existe uma porrada de métodos pra lidar com listas e mapas no Sass e a documentação deles é bem simples, se você quiser saber mais pode ler esse outro artigo que aborda algumas delas.

Segundo passo: montar o loop
Primeiro vamos identificar o que no botão é o código base, aquele que seja comum entre todos, pois para sermos DRY (não repetir código à toa). Para isso, não podemos permitir que hajam vários seletores com o mesmo código e para o mesmo fim.

.btn {
border: none;
border-radius: 8px;
cursor: pointer;
font-size: 1rem;
height: 44px;
min-width: 120px;
padding: 0 10px;
width: auto;
}

Agora precisamos criar o loop. Lembra que o nosso mapa tem três itens, né? Vamos iterar, ou seja, visitar cada uma das listas desse mapa e trazer cada um desses itens para variáveis que possamos usar.

.btn {
align-self: flex-end;
border: none;
border-radius: $default-radius;
cursor: pointer;
font-size: 1rem;
height: 44px;
margin-top: 28px;
min-width: 120px;
padding: 0 10px;
width: auto;
@each $name, $bg, $color in $buttons-map {
// Para cada NOME, BACKGROUND e COR em buttons-map
}
}

Se você se perguntou por que eu coloquei uma variável “nome”, é aqui que vamos utilizar essa variável com uma propriedade mara do Sass: a interpolação. Variáveis usadas dentro da interpolação vão ser compiladas e o resultado vai ser incorporado no código. Funciona como o template string em outras linguagens.

.btn {
align-self: flex-end;
border: none;
border-radius: $default-radius;
cursor: pointer;
font-size: 1rem;
height: 44px;
margin-top: 28px;
min-width: 120px;
padding: 0 10px;
width: auto;
@each $name, $bg, $color in $buttons-map {
&__#{$name} { // Aqui vai o nome do modifier
background-color: $bg; // aqui vai o background do botão
box-shadow: 1px 1px 6px 1px rgba(15, 15, 35, .1);
color: $color; // Aqui vai a cor do botão
transition:
background 0.15s ease-in-out,
box-shadow 0.15s ease-in-out;
}
}

Dessa forma, quando o Sass for compilado e esse loop computado, ele vai gerar as seguintes classes:

.btn {}
.btn__primary {}
.btn__success {}
.btn__danger {}
// ...

E você as utiliza assim:

<button class="btn btn__primary">Comprar</button>

Mas não vamos parar por aqui, né?
Você também consegue colocar as interações no loop:

.btn {
align-self: flex-end;
border: none;
border-radius: $default-radius;
cursor: pointer;
font-size: 1rem;
height: 44px;
margin-top: 28px;
min-width: 120px;
padding: 0 10px;
width: auto;
@each $name, $bg, $color in $buttons-map {
&__#{$name} {
background-color: $bg;
box-shadow: 1px 1px 6px 1px rgba(15, 15, 35, .1);
color: $color;
transition:
background 0.15s ease-in-out,
box-shadow 0.15s ease-in-out;
&:hover {
background-color: darken($bg, 5%);
box-shadow: 3px 3px 8px -7px rgba(15, 15, 35, .3);
}
&:active {
background-color: darken($bg, 10%);
}
&:focus,
&:focus-within {
box-shadow: 0 0 0 3px darken($bg, 10%);
outline: none;
}
&:disabled {
border: none;
cursor: default;
opacity: 0.55;
pointer-events: none;
user-select: none;
}
}
}

Aqui o pulo do gato é: ao invés de escrever a versão mais escura da cor ao fazer hover dentro do mapa, você pode usar uma função de cor do Sass pra tal, como darken(<cor>, <% de escurecimento>) ou mix(<cor1>, <cor2>, <% de mistura>). Tem muito mais exemplos na documentação e neste meu post.

3. Abuse do mixins

Geralmente os mixins são bons em duas ocasiões:

  • Quando você precisa repetir o mesmo código várias vezes com diferentes valores.
  • Quando você precisa repetir o mesmo código em diversos lugares, mas em alguns em específico você precisa acrescentar coisas.

Um mixin de Sass possui a seguinte sintaxe:

// Declaração simples que injeta regras CSS ou uma classe dentro do lugar que você a inserir
@mixin nome-mixin {
}// E usamos o mixin assim
.element {
@include nome-mixin();
}
// Podemos passar variáveis para o mixin@mixin background($color) {
background-color: $color;
}
// E com valores default
@mixin background($color: white) {
background-color: $color;
// Caso você declare o mixin sem parâmetros, a cor será a padrão
}
// E por fim, com um bloco
@mixin background($color: white) {
background-color: $color;
@content
// Content sinaliza que podemos acrescentar coisas na declaração
do mixin
}
// E usamos assim
.element {
@include background('#CBDBAD') {
color: white;
}
}

Mixins podem ser muito poderosos! Imagine uma situação na qual você tem diversas <ul>, cada uma com 10 <li> e cada lista vai ter uma escala de cores. Podemos criar um mixin para gerar essa escala de 10 cores:

@mixin generate-color($name, $color) {
$number: 100;
@for $i from 0 through 9 {
$counter: $i * 10%;
// Para cada numero de 1 a 9, a cor fica mais clara em 10%
$new-color: change($color, $lightness: $counter); .#{unquote($name)}-#{$number * $i} {
// Nesse caso a classe ficará algo como .blue-100
background-color: $color;
}
}
}
@include generate-color("blue", $paleblue, "color");

Se quiser saber mais sobre essas funções que eu usei, só acessar na documentação o change-color e o unquote.

E é isso! Espero que essas dicas te ajudem a explorar o Sass muito além do CSS aninhado. Gostou? Acrescentaria algo? Achou algum erro? Fique à vontade para deixar nos comentários.

E se você quiser trabalhar e aprender junto com um time muito bom de JavaScript aqui na Concrete, é só dar uma olhada aqui e se candidatar a alguma de nossas vagas. Vamos aprender juntos! Até a próxima.

--

--

Nós desenvolvemos produtos digitais com inovação, agilidade e excelentes práticas, para que o mercado brasileiro e latino-americano acompanhe a velocidade do mercado digital mundial.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Camilo Micheletto

Camilo Micheletto

Educador/educando, perseguidor de futuros indômitos e empreendedor.