Reduzir a repetição de estilo com funções CSS

Recursos da Web: @function

Manter folhas de estilo grandes geralmente leva a uma lógica repetitiva, especialmente ao lidar com tokens de sistema de design, como gradientes ou padrões de layout responsivos.

A regra @ @function do CSS permite encapsular essa lógica em funções reutilizáveis e parametrizadas, tornando o CSS mais fácil de manter, consistente e DRY (Don't Repeat Yourself).

A sintaxe @function

Uma função personalizada é definida usando a regra @function seguida por um nome com traço e uma lista de parâmetros. A função retorna um valor usando a propriedade result.

@function --my-function(--input1 <length>, --input2: default-value) returns <length> {
  /* Logic goes here */
  result: var(--input1);
}

Principais conceitos

  • Parâmetros: precisam começar com um traço duplo (--).
  • Padrões: é possível fornecer valores padrão usando dois pontos (:).
  • Resultado: a propriedade result determina o valor que a função retorna. O último result declarado no corpo da função vence.
  • Escopo: os parâmetros e as variáveis definidos dentro da função têm escopo local.
  • Tipos: é possível exigir que os parâmetros e o valor retornado correspondam a um tipo de CSS com notação de colchetes (por exemplo, <color>) e permitir vários tipos com a função type (por exemplo, type(<number> | <percentage>)).

Exemplos práticos

1. Tokens do sistema de design (gradientes)

Garanta gradientes de cor consistentes no app encapsulando a lógica de gradiente. O --angle fornece um valor padrão para garantir consistência que pode ser substituído.

@function --fancy-gradient(--start-color <color>, --end-color <color>, --angle: 98deg) returns <image>{
  result: linear-gradient(in oklab var(--angle), var(--start-color), var(--end-color) );
}

.card {
  background: --fancy-gradient(#ed73d7, #5d87e9);
}

2. Lógica de layout condicional

É possível usar @media ou outras consultas diretamente em uma função para retornar valores diferentes com base no ambiente. Ao usar a lógica condicional em uma função, observe que o @function não "retorna" no primeiro valor de result, mas segue a cascata do CSS e é resolvido para o último valor que corresponde com base no tamanho da tela, do contêiner ou de outra consulta.

@function --grid-template(--count <number>){
  /* MANDATORY: Put default value first. */
  result: 1fr; /* Default: stack */
  @media (min-width: 800px) {
    result: repeat(var(--count), 1fr); /* Grid on larger screens */
  }
}

main {
  display: grid;
  grid-template-columns: --grid-template(2);
}

Práticas recomendadas

  • Use nomes com traços: sempre use -- como prefixo nos nomes e parâmetros das funções.
  • Forneça valores padrão: torne suas funções mais robustas fornecendo valores padrão adequados.
  • Descomplique: use funções para lógicas que são repetidas ou complexas. Não complique demais os pares de propriedade-valor simples.
  • Use tipos: verifique se os parâmetros e os valores de retorno são dos tipos esperados.
  • Considere alternativas pré-compiladas: para funções que não dependem de entrada do usuário, consultas de mídia ou outras variações do lado do cliente, considere usar um pré-compilador CSS para evitar trabalho desnecessário no cliente.

Estratégias de fallback

Em navegadores que não são compatíveis com funções CSS, os valores definidos usando essas funções serão inválidos. Para oferecer suporte a outros navegadores, forneça primeiro um valor substituto para a propriedade. Isso será substituído em navegadores com suporte à função CSS.

.card {
  /* Provide fallback, in this case a solid color. */
  background: #5d87e9;
  background: --fancy-gradient(#ed73d7, #5d87e9);
}

main {
  /* Provide fallback, in this case a simple stacked default. */
  grid-template-columns: 1fr;
  grid-template-columns: --grid-template(2);
}

Se for necessário reduzir a repetição de estilo e, ao mesmo tempo, oferecer suporte a outros navegadores, considere um pré-compilador CSS com funções, como o Sass.