Na primeira parte parte da minissérie com dicas de Sass, mostramos as 8 primeiras dicas que talvez você não conhecia para levar seu código Sass ao próximo nível.
Agora, na segunda e última parte, aprenda mais 8 dicas de Sass que, com certeza, vão ajudar bastante e facilitar sua vida no front end.
9. Argumentos variáveis para funções/mixins
Argumentos variáveis funcionam da mesma maneira que em outras linguagens que suportam o recurso: quaisquer argumentos extras para uma chamada de função/mixin são agrupados em uma lista e atribuídos ao argumento com um sufixo …
.
Sass
1 2 3 4 5 6 7 8 9 10 11 12 13 |
@mixin config-icon-colors($prefix, $colors...) { @each $i in $colors { .#{$prefix}#{nth($i, 1)} { color: nth($i, 2); } } } @include config-icon-colors('icon-', 'save' green, 'cancel' gray, 'delete' red ); |
CSS compilado
1 2 3 4 5 6 7 8 9 10 11 |
.icon-save { color: green; } .icon-cancel { color: gray; } .icon-delete { color: red; } |
O helper acima pode ser usado para configurar cores para ícones, por exemplo, sem ter que se repetir.
Ele funciona passando um número variável de argumentos (após o primeiro, required); espera-se que cada um desses argumentos seja um array de dois itens (na notação JavaScript, por exemplo, seria ['save', 'green']
).
Na verdade, a sintaxe …
também funciona durante o tempo de chamada (call-time), em que expande uma lista em argumentos separados a serem usados no mixin de destino:
1 2 3 4 5 6 7 8 |
@mixin foobar($a, $b, $c) { // Recebe args $a = 5px, $b = red, e assim por diante. } $myArgs: 5px red "bla bla"; // Nesse ponto, é possível adicionar/remover argumentos programaticamente @include foobar($myArgs...); |
Talvez não haja tantos casos de uso para isso, mas a documentação tem um bom caso de uso para passar os argumentos atuais para outro mixin.
10. Argumentos de bloco de conteúdo para mixins
Desde a versão 3.2.0, o SCSS tem um argumento implícito de mixin acessível por meio da diretiva @content
.
Ele permite passar um bloco de conteúdo SCSS inteiro como um argumento para o mixin:
Sass
1 2 3 4 5 6 7 8 9 10 11 12 |
@mixin only-for-mobile { @media (max-width: 768px) { @content; } } @include only-for-mobile() { /* início @content */ p { font-size: 150%; } } /* fim @content */ |
CSS compilado
1 2 3 4 5 |
@media (max-width: 768px) { p { font-size: 150%; } } |
Este é um recurso muito poderoso, especialmente para o uso em frameworks, já que permite passar blocos arbitrários de estilo, envoltos (wrapped) em seletores específicos, podendo ser usados em loops, tornando condicional com @if
etc.
Também é possível misturar argumentos padrão e de bloco de conteúdo também:
1 2 3 4 5 6 7 8 9 10 11 |
@mixin only-for-mobile($breakpoint) { @media (max-width: #{$breakpoint}) { @content; } } @include only-for-mobile(480px) { p { font-size: 150%; } } |
11. Padrão de bloqueio de substituição de conteúdo
Considere um mixin que gere um seletor e alguns estilos para ele, permitindo que o chamador (caller) personalize o estilo, se necessário:
1 2 3 4 5 6 7 8 |
@mixin message($class, $color: yellow, $margin: 20px, $padding: 10px) { .message-#{$class} { border: 1px dotted $color; color: $color; margin: $margin; padding: $padding; } } |
Chamar este mixin usando argumentos de palavra-chave (veja a parte 1) é bastante conveniente, porque se os default forem bons, nenhum argumento extra precisa ser fornecido e, se não forem, só é preciso especificar os argumentos que deseja substituir:
1 |
@include message("subtle", $margin: 5px); |
Mas isso requer listar todas as propriedades substituíveis na assinatura do mixin. No entanto, os argumentos do bloco de conteúdo permitem substituições arbitrárias sem a “selva” de argumentos:
Sass
1 2 3 4 5 6 7 8 9 10 11 12 13 |
@mixin message($class) { .message-#{$class} { border: 1px dotted yellow; color: yellow; margin: 20px; padding: 10px; @content; } } @include message("subtle") { margin: 5px; } |
CSS compilado
1 2 3 4 5 6 7 |
.message-subtle { border: 1px dotted yellow; color: yellow; margin: 20px; padding: 10px; margin: 5px; } |
A boa e velha Cascata de CSS substitui a propriedade (a última margem substitui a anterior).
Além disso, não existe a limitação de substituir as propriedades que o autor do mixin pensou; na verdade, isso também permite passar blocos aninhados:
Sass
1 2 3 4 5 |
@include message("actionable") { button { float: right; } } |
CSS compilado
1 2 3 4 5 6 7 8 9 10 |
.message-actionable { border: 1px dotted yellow; color: yellow; margin: 20px; padding: 10px; } .message-actionable button { float: right; } |
Esse pattern pode ser útil em qualquer código que produza um estilo não trivial com seletores gerados, uma vez que permite ao usuário um ponto de personalização além do que o autor da biblioteca previu.
Note, entretanto, que em casos simples (onde nenhum seletor é emitido dentro do mixin), é bastante desnecessário, já que qualquer substituição pode ser feita apenas usando a cascata CSS padrão.
12. Media query bubbling
Os blocos @media
não precisam ser declarados no nível raiz da folha de estilo:
Sass
1 2 3 4 5 6 7 8 9 10 11 12 13 |
body { article { p { font-size: 100%; color: black; padding: 10px; @media (max-width: 768px) { font-size: 150%; } } } } |
CSS
1 2 3 4 5 6 7 8 9 10 11 |
body article p { font-size: 100%; color: black; padding: 10px; } @media (max-width: 768px) { body article p { font-size: 150%; } } |
Observe como o compilador “borbulha” (“bubbles up“) o bloco @media
para o nível raiz (já que o CSS regular não suporta o aninhamento do seletores) e, dentro dele, produz todos os estilos encontrados no bloco @media
no código-fonte SCSS.
Isso é muito útil, pois permite fazer ajustes específicos de mídia em quase qualquer lugar em seu estilo, exatamente onde eles são relevantes, em vez de coletar todos os ajustes no final da folha de estilo e esperar que seus seletores permaneçam em sincronia com aqueles que eles estão substituindo (eles não irão).
13. Aninhamento de media query
O mecanismo de bubbling mencionado acima também leva em consideração o aninhamento e combina todas as queries aplicáveis com o operador and
:
Sass
1 2 3 4 5 6 7 8 9 |
p { @media (max-width: 768px) { font-size: 150%; @media (orientation: landscape) { line-height: 75%; } } } |
CSS
1 2 3 4 5 6 7 8 9 10 11 |
@media (max-width: 768px) { p { font-size: 150%; } } @media (max-width: 768px) and (orientation: landscape) { p { line-height: 75%; } } |
14. Estendendo seletores
Sass permite estender seletores, copiando e combinando seletores no CSS compilado.
Curiosamente, embora o mecanismo seja (obviamente) muito diferente, a semântica de @extend
é bastante análoga às linguagens de programação orientadas a objetos tradicionais (como Java e outras):
Sass
1 2 3 4 5 6 7 8 |
.animal { background: gray; } .cat { @extend .animal; color: white; } |
CSS compilado
1 2 3 4 5 6 7 8 |
.animal, .cat { background: gray; } .cat { color: white; } |
Ou seja, .cat
tem todas as propriedades de sua “classe pai” .animal
, mais quaisquer propriedades específicas que ele adiciona ou substitui.
Enquanto no CSS normal é preciso fazer referência à classe extensível e à classe pai (por exemplo, <div class="animal cat">
), agora simplesmente se nomeia a classe exata que se deseja (<div class="cat">
).
O que ele herda (ou não) depende da definição de .cat
e pode ser alterado posteriormente, sem tocar na marcação.
A substituição de propriedades na “classe filha” funciona devido ao estilo em cascata no navegador: o estilo para o mesmo seletor que vem depois no arquivo sempre vence o estilo que veio antes dele.
Talvez um pouco não intuitivamente, isso realmente funciona bem, mesmo se os seletores combinados tiverem especificidades diferentes (pense em .class
estendendo um #id
). Estender seletores pode ser preferível a usar mixins para obter o mesmo efeito:
Sass
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
@mixin animal { background: gray; border: 1px solid red; color: red; font-size: 50px; font-weight: bold; padding: 20px; } .cat { @include animal; color: white; } .dog { @include animal; color: black; } |
CSS compilado
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
.cat { background: gray; border: 1px solid red; color: red; font-size: 50px; font-weight: bold; padding: 20px; color: white; } .dog { background: gray; border: 1px solid red; color: red; font-size: 50px; font-weight: bold; padding: 20px; color: black; } |
Observe como apenas a última propriedade (color
) é diferente, o resto é o mesmo. Conforme se define mais tipos de animais, a quantidade de propriedades de estilo repetidas na saída CSS continua crescendo.
Isso contrasta com a forma como a extensão do seletor resolveria o mesmo problema:
Sass
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
.animal { background: gray; border: 1px solid red; color: red; font-size: 50px; font-weight: bold; padding: 20px; } .cat { @extend .animal; color: white; } .dog { @extend .animal; color: black; } |
CSS compilado
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
.animal, .cat, .dog { background: gray; border: 1px solid red; color: red; font-size: 50px; font-weight: bold; padding: 20px; } .cat { color: white; } .dog { color: black; } |
Lembrando que a extensão de seletor permite integrações em bibliotecas CSS de terceiros (que não precisam ser especificamente projetadas para extensão) ou mesmo escritas em SCSS.
Por exemplo:
1 2 3 4 5 |
@import "bootstrap.scss"; button { @extend .btn; } |
15. Placeholder selectors
Como nos exemplos acima, a classe-base .animal
não é usada em nenhum lugar diretamente (apenas por meio de suas classes filhas), é possível economizar código na copilação CSS através de um recurso chamado placeholder selectors.
Veja neste exemplo:
Sass
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
%animal { background: gray; // ... } .cat { @extend %animal; color: white; } .dog { @extend %animal; color: black; } |
CSS compilado
1 2 3 4 5 6 7 8 9 10 11 12 13 |
.cat, .dog { background: gray; /* ... */ } .cat { color: white; } .dog { color: black; } |
Como %animal
é um placeholder selector, ele não aparece na saída da compilação.
16. Herança múltipla
Um seletor pode herdar de vários outros seletores — ou seja, o SCSS oferece suporte a herança múltipla. Para cada @extend
, o seletor atual é anexado ao seletor que está sendo estendido.
Quando combinado com placeholder selectors, isso permite abstrações poderosas. Isso talvez seja mais bem entendido por meio de um exemplo:
Framework (fictício)
1 2 3 4 5 6 7 8 9 10 11 12 13 |
%mfw-standing-out { font-size: 150%; font-style: italic; padding: 25px; } %mfw-slightly-shadowed { @include box-shadow(black 2px 2px 10px); } %mfw-rounded { @include border-radius(25px); } |
Projeto usando o framework
1 2 3 4 5 6 7 |
#join-button { @extend %mfw-standing-out; @extend %mfw-slightly-shadowed; @extend %mfw-rounded; background: green; color: white; } |
Esta abordagem de se trabalhar com estilos traz alguns benefícios notáveis — autodocumentação; isolamento de nomenclatura; redução de repetição –, mas, claro, também com seu lado negativo — depurabilidade diminuída; falta de parâmetros.
Conclusão
Nesta minissérie com dicas de Sass para facilitar sua vida, mostramos recursos que estão presentes já há tempos no pré-processador queridinho dos devs front end, mas que, não necessariamente, são conhecidas e/ou consideradas pela maioria.
Contando com a primeira parte, essas foram as 16 dicas de Sass:
- Prefixando a referência ao ascendente
- Expansão de variáveis em seletores
- Variáveis default
- Diretivas de controle
- O tipo de data “list”
- Funções customizadas
- Valores padrão de argumentos
- Argumentos com palavras-chave (keywords)
- Argumentos variáveis para funções/mixins
- Argumentos de bloco de conteúdo para mixins
- Padrão de bloqueio de substituição de conteúdo
- Media query bubbling
- Aninhamento de media query
- Estendendo seletores
- Placeholder selectors
- Herança múltipla
Como em todas as listas com dicas, conheça cada uma delas e pondere sobre quais usar e quais não usar em cada projeto concreto que apareça — algumas, claro, podem ser usadas (de repente, com adaptações) para compor frameworks ou bibliotecas.
E você, conhece mais alguma dica de Sass e quer contar pra gente? Coloca nos comentários!