Iniciando no Sass com os dois pés na porta - Funções
Tags: css, beginners, bem, sass
Published: 2020-09-01 02:06:29

_Caso você tenha ainda não tenha lido o post anterior, ele [tá aqui](https://dev.to/lixeletto/iniciando-no-sass-com-os-dois-pes-na-porta-pe7) e nele eu ensino a configurar um compilador maroto, entender variáveis, escopo e loopings. Nesse artigo eu vou cobrir funções, mixins, blocos e cálculos detalhadamente mas sem fritar a sua mente._

## Funções
Funções do Sass funcionam exatamente como as do javascript - podem ou não receber parâmetros e **sempre retornam um valor**, esse valor pode ser uma cor, um número, uma lista, um mapa ou uma string. As funções de Sass não reagem a eventos do DOM como as do Javascript pois ao compilar, pois o compilador avalia essas funções, retorna o resultado e passa o resultado pra CSS normal. O Sass possui também uma série de funções nativas e funções estendidas do CSS.

```scss
// funções de cor

.card {
  background: tomato;
  &:hover {
    background: darken(tomato, 10%);
  }
}


//funções matemáticas

.card {
  height: random(100) * 1px;
}


// funções estendidas do CSS

.card {
  font-size: clamp(1.75rem, 3vw, 2.1rem);
}
```

É possível também escrever as funções de forma aninhada:
```scss
@for $i from 1 through 4 { 
  .color-#{$i} {
    background-color: hsl(
      floor(random(360)),
      floor(random(100) * 1%),
      floor(random(100) * 1%));
  }
}
```

O que tá rolando ai (se você entendeu o que tá rolando pode pular):
1. O loop `@for` diz literalmente que: *PARA CADA n ENTRE 1 e 4 FAÇA*

2. Na primeira iteração a variável $i recebe o número 1, o seletor dentro do loop `.color-` está interpolado com a variável `$i` que ao ser avaliada sua interpolação resulta no seletor `.color-1`.

3. Dentro de  `background-color` tem uma função HSL cujo o todos parâmetros recebem uma função `floor()`. Essa função recebe um número como argumento e retorna um inteiro mais próximo dele.

4. A função `random()` por sua vez recebe um número como argumento e gera um número decimal aleatório entre 1 e o número recebido.

Tudo isso gera uma paleta de cores aleatória:

{% codepen https://codepen.io/camilo-micheletto/pen/qBZRrVX %}

Só que essa paleta é estática, o loop `@for` e as funções `random()` e `floor()` foram avaliadas pra valores *estáticos* de CSS, ou seja, uma vez no browser essas funções nunca mais serão avaliadas pois já estarão compiladas (A não ser que tu recarregue a página).

Você também pode criar suas próprias funções que podem receber nenhum, múltiplos ou um número indefinido de argumentos:

```scss
//Uma função pode receber um ou nenhum argumento
.@function bigger-size($size) {
  @return $size * 2;
}


//Pode receber valores padrões caso não recebam argumentos
@function analog-color($color, $num: 30) {
  //Caso $num não seja preenchido ele será igual a 30

  $new-color: hue-adjust($color, #{$num}deg);

  @return $new-color;
}

//Pode receber uma quantidade n de argumentos
@function auto-height($height, $selectors...) {
  //Essa função recebe uma altura e uma quantidade n de seletores
}
```

##Mixins
Mixins são funções que não retornam valores mas sim estilos. Um mixin recebe um nome e pode receber argumentos. O intuito do mixin é maximizar a sua capacidade de reutilizar regras de CSS com valores diferentes, tornando seu código mais limpo e menos repetitivo ou DRY (Don't Repeat Yourself).

```scss
//Um mixin pode receber um ou nenhum argumento
@mixin colorize($cor){
  //...
}


//Pode receber valores padrões caso não recebam argumentos
@mixin square($size, $radius: 0) {
  //Caso $radius não seja preenchido ele será igual a 0
}


//Pode receber uma quantidade n de argumentos
@mixin auto-height($height, $selectors...) {
  //Essa função recebe uma altura e uma quantidade n de seletores
}
```

E pra utilizar um mixin, você utiliza o `include()`

```scss
$main-style: #33ffcc;

@mixin navbar-colors($color) {
  background: $color;
  color: complement($color);
}

.navbar {
  @include navbar-colors($main-style);
}

//CSS
.navbar {
  background: #33ffcc;
  color: #ff3366;
}
```

O [David Halford](http://www.davidhalford.com/thoughts/2013/auto-contrasting-text/) criou uma função de Sass que avalia uma cor em relação ao fundo e retorna preto ou branco de acordo com o contraste com o fundo. Essa função é ótima pra automatizar a seleção de cor de fonte privilegiando a legibilidade. A formula dessa função tá documentada [aqui no site da W3](https://www.w3.org/TR/AERT/#color-contrast) caso você queira conhecer mais.

```scss
//Definição do mixin

@mixin text-contrast($color) {
  $color-brightness: round((red($color)*299)+(green($color)*587)+(blue($color)*114)/1000);

  $light-color: round((red(#ffffff)*299)+(green(#ffffff)*587)+(blue(#ffffff)*114)/1000);

  @if abs($color-brightness) < ($light-color/2){
    color: white;
  } @else {
    color: black;
  }
}

//Uso
.card {
  background: #fafafa;
  .card__text {
      @include text-contrast($card-color);
  }
}
```

O que tá rolando nessa função?

1. A função `round()` arredonda o número recebido como argumento para o número inteiro mais próximo.

2. As funções `red()`, `green()` e `blue()` recebem uma cor como argumento e retornam o seu respectivo canal.

3. As funções de cor serão avaliadas e multiplicadas por seus respectivos valores, o produto dessa soma será dividido por 1000.

4. A função `abs()` recebe como argumento um número e retorna seu valor absoluto ou seja se negativo, será convertido para positivo. 

5. SE o valor absoluto da sua cor for MENOR do que o da cor mais clara dividido por 2, ele retornará ```css color: white```, SENÃO ```css color: black```

Esse exemplo funcionando fica assim:
{% codepen https://codepen.io/camilo-micheletto/pen/wvGgJVw %}

## Content
Vamos imaginar uma situação que vamos criar um mixin de animação CSS usando @keyframes:

```scss
@mixin animation($name) {
  @keyframes $name {
     from { opacity: 0; }
     to   { opacity: 1; }
  }
}
```

Só que nesse caso, se eu quiser fazer uma animação diferente eu teria que criar outro mixin né? E se dentro dos @keyframes pudéssemos passar um bloco de código pra ele executar? Ai é que entra a diretiva `@content`

```scss
@mixin animation($name) {
  @keyframes #{$name} {
     @content
  }
}

// Uso

.card {
  transition: animate .5s forwards ease-in;

  @include animation(animate) {
     from { opacity: 0; }
     to   { opacity: 1; }
  }
}
```

Só que só fazendo dessa maneira, compensa usar só o @keyframes sozinho né? Mas e se a gente quisesse colocar os _prefixes_ pra garantir que essas animações funcionem bem em todos os navegadores?

```scss
@mixin animation($name) {
  @-webkit-keyframes #{$name} {
    @content;
  }

  @-moz-keyframes #{$name} {
    @content;
  }

  @keyframes #{$name} {
    @content;
  }
}

// Uso

.card {
  transition: animate .5s forwards ease-in;

  @include animation(animate) {
     from { opacity: 0; }
     to   { opacity: 1; }
  }
}
```

Agora esse código gerará os três @keyframes com seus respectivos prefixes. Você também consegue passar argumentos para o @content, é recomendado que se você for passar mais de um, você passe como $map, você pode ler mais sobre isso na [documentação oficial](https://sass-lang.com/documentation/at-rules/mixin#content-blocks).

Mixins e funções podem facilitar muito a sua vida e tornar seus códigos cada vez mais modularizáveis e limpos, esses conceitos são um pouco mais complicados que os anteriores, então sugiro ler a [documentação sobre funções e mixins](https://sass-lang.com/documentation/at-rules) (que é bastante boa) porque lá eles tem bastante exemplos, recomendo principalmente para as [funções nativas de cores](https://sass-lang.com/documentation/modules/color), que são as mais utilizadas.

---------------
No próximo artigo eu vou usar o que vimos aqui pra construir um gerador de paleta de cores para componentes, que nem [esse aqui](https://codepen.io/camilo-micheletto/pen/xxVRmjX). Se isso foi útil pra você, compartilha com quem você acha que isso vai ajudar. Dúvidas, sugestões? Comente ou manda um salve lá no meu Twitter @lixeletto.