Reduce la repetición de estilos con funciones de CSS

Funciones web: @function

Mantener hojas de estilo grandes suele generar una lógica repetitiva, en especial cuando se trabaja con tokens de sistemas de diseño, como gradientes o patrones de diseño responsivo.

La regla-at @function de CSS te permite encapsular esta lógica en funciones reutilizables y parametrizadas, lo que hace que tu CSS sea más fácil de mantener, coherente y DRY (Don't Repeat Yourself).

La sintaxis de @function

Una función personalizada se define con la regla @function seguida de un nombre con guiones y una lista de parámetros. La función devuelve un valor con la propiedad result.

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

Conceptos clave

  • Parámetros: Deben comenzar con un guion doble (--).
  • Valores predeterminados: Puedes proporcionar valores predeterminados con dos puntos (:).
  • Resultado: La propiedad result determina el valor que devuelve la función. La última result declarada en el cuerpo de la función gana.
  • Alcance: Los parámetros y las variables definidos dentro de la función tienen un alcance local.
  • Tipos: Puedes exigir que los parámetros y el valor que se muestra coincidan con un tipo de CSS con notación de corchetes (p.ej., <color>) y permitir varios tipos con la función type (p.ej., type(<number> | <percentage>)).

Ejemplos prácticos

1. Tokens del sistema de diseño (gradientes)

Encapsula la lógica de gradientes de color para garantizar que sean coherentes en toda la app. --angle proporciona un valor predeterminado para brindar coherencia que se puede anular.

@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 diseño condicional

Puedes usar @media o cualquier otra consulta directamente dentro de una función para devolver diferentes valores según el entorno. Cuando uses la lógica condicional en una función, ten en cuenta que @function no "devuelve" el primer valor de result, sino que sigue la cascada de CSS y se resuelve en el último valor que coincide según el tamaño de la pantalla, el tamaño del contenedor o cualquier otra 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ácticas recomendadas

  • Usa nombres con guiones: Siempre agrega el prefijo -- a los nombres y parámetros de tus funciones.
  • Proporciona valores predeterminados: Haz que tus funciones sean más sólidas proporcionando valores predeterminados razonables.
  • Mantén la simplicidad: Usa funciones para la lógica que realmente se repite o es compleja. No compliques demasiado los pares propiedad-valor simples.
  • Usa tipos: Asegúrate de que tus parámetros y valores de retorno sean de los tipos esperados.
  • Considera alternativas precompiladas: Para las funciones que no dependen de la entrada del usuario, las consultas de medios o cualquier otra variación del cliente, considera usar un precompilador de CSS para evitar realizar trabajo innecesario en el cliente.

Estrategias de resguardo

En los navegadores que no admiten funciones de CSS, los valores establecidos con estas funciones no serán válidos. Para admitir otros navegadores, primero proporciona un valor de resguardo para la propiedad. Esto se anulará en los navegadores que admitan funciones de 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);
}

Si es un requisito reducir la repetición de estilos y, al mismo tiempo, admitir otros navegadores, considera un precompilador de CSS con funciones, como Sass.