Guía educativa de @function
@function: fórmulas reutilizables con valores CSS
Una custom property guarda un valor; una función CSS recibe argumentos y calcula un valor en el punto de uso. Aprende a definir su firma, resolver result y conservar una alternativa cuando falte soporte.
Modelo mental
Definir una función no aplica estilos: hay que llamarla dentro de un valor de propiedad.
- Firma y argumentos
--guide-space(--step <number>: 2) declara un parámetro. --guide-space(1) le pasa un argumento.
- Resolución local
var(--step) consulta el parámetro; los valores locales y las condiciones determinan result.
- Valor de propiedad
El resultado sustituye la llamada en padding. Debe cumplir tanto returns como la gramática de padding.
Los nombres de función y parámetro empiezan por -- y distinguen mayúsculas. La llamada usa paréntesis, no var(--nombre-de-función). Define @function fuera de las reglas de estilo y úsala donde aceptarías un valor CSS; puede no recibir parámetros.
Parámetros, tipos y valores por defecto
La firma describe las entradas y returns restringe el valor de salida.
Los parámetros se separan con comas. El tipo es opcional: sin él se acepta type(*). Un default va después de dos puntos y debe respetar el tipo. Aquí --step es <number>, pero el cálculo produce <length>. Los parámetros se leen con var(); la llamada recibe valores, no nombres de parámetros.
Una escala de espacio con argumento opcional
--guide-space(): default 2
--guide-space(1): argumento 1
Función CSS nativa: compara el espacio con el resultado esperado.
Fallback base: 1rem de padding; la sintaxis de llamada no está disponible.
Omitir el argumento usa 2; pasar 1 lo sustituye. Un argumento incompatible también puede activar el default; sin default, un argumento obligatorio ausente o incompatible invalida la llamada. <length> no admite porcentajes: usa <length-percentage> si necesitas ambos. type(<number> | <percentage>) permite una unión, pero tu fórmula aún debe manejar ambos tipos.
Ámbito: parámetros, variables locales y elemento
La función se evalúa en el contexto de la llamada, no como un valor fijado en :root.
var() busca primero una variable local, después un parámetro y después las custom properties disponibles en el punto de llamada. Una variable local oculta un parámetro del mismo nombre; el parámetro oculta la propiedad del elemento. Los locales no se publican como propiedades en el DOM.
Misma función, distinta unidad por componente
--unit: 0.5rem; parámetro --step: 2
--unit: 1rem; parámetro --step: 2
Función CSS nativa: compara el espacio con el resultado esperado.
Fallback base: 1rem de padding; la sintaxis de llamada no está disponible.
--computed-space solo existe durante la evaluación. Evita nombres locales que oculten parámetros por accidente y pasa argumentos explícitos cuando quieras que las dependencias sean visibles. El ámbito de las variables no convierte la definición de @function en una regla local a un selector; usa nombres propios para evitar colisiones entre definiciones.
result y ramas condicionales
El último result aplicable gana; no existe un return anticipado como en JavaScript.
Coloca primero el result general y después el condicional. En este ejemplo @media cambia el valor cuando el viewport mide menos de 700px. Si mueves el result general al final, sobrescribe la rama incluso cuando la condición se cumple. También puedes variar variables locales y resolver un único result al final.
Espacio responsive con dos resultados
Viewport < 700px: 0.75rem; desde 700px: 1.5rem
Función CSS nativa: compara el espacio con el resultado esperado.
Fallback base: 1rem de padding; la sintaxis de llamada no está disponible.
La condición mira el viewport del documento que ejecuta la función, no la anchura de la tarjeta. En el playground, la función vive dentro de un iframe: @media consulta ese iframe. @supports y otras reglas condicionales admitidas tienen su propia compatibilidad; este ejemplo solo demuestra @media. if() es otra forma de elegir un valor y no se necesita para esta receta.
Comparativas
Elige la abstracción según lo que realmente se repite.
Usa una custom property para un token o un valor configurable por cascada y herencia. Para una cuenta sencilla, calc() con variables en el propio componente suele bastar. @function aporta una firma reutilizable con argumentos, tipos, valores por defecto y lógica que puede devolver resultados distintos en cada llamada.
Alternativa simple con custom properties
En esta alternativa la fórmula se calcula en el elemento que recibe padding. Si defines un valor compuesto en :root y lo heredas, sus referencias se resuelven allí: cambiar una variable dependiente en un descendiente no recalcula automáticamente aquel valor heredado. Una función calcula en el punto de llamada. Ninguna de las dos opciones necesita JavaScript.
Un fallback protegido
Separa falta de sintaxis de una función que se acepta, pero devuelve un valor inválido.
Las tres previews definen padding: 1rem fuera del bloque de mejora. Solo aplican la llamada dentro de @supports (padding: --nombre()). En un motor sin sintaxis de funciones personalizadas, la condición no se cumple y la base queda intacta. Este test comprueba aceptación sintáctica: no verifica que ese nombre exista, sus argumentos ni su resultado.
Antiejemplo: la declaración anterior no siempre te salva
Ejemplo incorrecto deliberado, sin preview: si el motor acepta la llamada pero la función no existe, padding queda inválido al calcularse y usa su valor inicial, 0; no vuelve a 1rem.
El guard tampoco rescata una llamada rota en un navegador compatible. Comprueba el valor computado y prueba argumentos y ramas reales. var(--token, alternativa) no es un try/catch de cualquier error en una propiedad. Los ejemplos usan @supports sobre padding para no exigir además soporte de at-rule(@function).
Errores frecuentes
Diagnostica firma, resolución y propiedad de destino por separado.
La rama condicional nunca cambia el resultado
- Resultado esperado
- El valor se adapta cuando coincide @media.
- Causa
- Un result general posterior sobrescribe el condicional; result no detiene la evaluación.
- Solución
- Coloca primero la base y luego las excepciones, o cambia locales y calcula result al final.
La función existe, pero la propiedad no se aplica
- Resultado esperado
- El resultado cumple el tipo declarado y la propiedad receptora.
- Causa
- Un argumento obligatorio, returns o la gramática de destino no encaja; devolver una longitud no la hace válida para color.
- Solución
- Revisa argumentos/defaults, tipo de salida y valor computado. Prueba una llamada mínima antes de añadir condiciones.
La variable devuelve otro valor o no aparece fuera
- Resultado esperado
- Cada nombre se resuelve en el ámbito previsto.
- Causa
- Un local o parámetro oculta la propiedad del elemento, o intentas leer un local desde fuera de la función.
- Solución
- Renombra variables para evitar colisiones y devuelve el dato mediante result. No esperes que un local se herede en el DOM.
El fallback desaparece en un navegador compatible
- Resultado esperado
- La interfaz mantiene un valor útil con y sin la mejora.
- Causa
- La llamada supera @supports, pero falla al calcularse: el navegador no recupera la declaración previa.
- Solución
- Mantén una base fuera del guard y verifica también la llamada, los valores y las ramas en el motor que la acepta.
Soporte y compatibilidad
El estado general no certifica cada firma, rama ni valor devuelto.
@function tiene disponibilidad limitada. En la consulta del 22 de octubre de 2026, Web Platform DX registra Chrome y Edge desde 139, y ningún soporte estable en Firefox ni Safari. MDN BCD marca Safari como preview; eso no equivale a una versión estable disponible.
La tarjeta Baseline informa de la feature general. El aviso de cada ejemplo usa un test de sintaxis local; las medidas descritas requieren que su función se evalúe correctamente. Los fallbacks mantienen espacio legible, sin simular funciones con JavaScript. Revisa los datos enlazados antes de usarlo en producción: el borrador y las implementaciones pueden cambiar.