La regla @property
de CSS es una sencilla pero potente característica de una serie de API denominadas CSS Houdini (en referencia al famoso ilusionista que hacía cosas que parecían imposibles), mediante las cuales puedes realizar ciertas tareas que, en principio, eran imposibles de hacer sólo con CSS directamente en el navegador.
¿Qué es la regla @property
?
La regla @property
nos permite indicar al navegador el tipo de dato, así como algunos datos relacionados, que tiene una variable CSS. Si conoces la idea base de Typescript, que es dotar de una comprobación de tipos a Javascript, la idea de la regla @property
es muy similar.
¿Para qué podemos necesitar esto en CSS? Existe un caso particular donde se ve muy claro su utilización. Imagina que queremos crear una animación para mover un elemento, y el valor que vamos a animar es un tamaño que está guardado en una variable CSS. El navegador desconoce el tipo de dato que está guardado en las variables CSS, por lo que no aplicará la animación sino que saltará de golpe entre el primer valor y el último:
.element {
--x: 0;
width: 150px;
height: 150px;
background: red;
animation: move 2s alternate infinite;
translate: var(--x) 0;
}
@keyframes move {
to { --x: 300px; }
}
<div class="element"></div>
Sin embargo, con la regla @property
podemos indicarle específicamente de que tipo de dato se trata, y que actúe como corresponde, entendiendo que esa variable contendrá un tamaño, y como consecuencia, soportando la animación que antes no soportaba:
.element {
--x: 0;
width: 150px;
height: 150px;
background: red;
animation: move 2s alternate infinite;
translate: var(--x) 0;
}
@keyframes move {
to { --x: 300px; }
}
@property --x {
syntax: "<length>";
inherits: true;
initial-value: 0
}
<div class="element"></div>
Además, ofrece otras ventajas que iremos explicando a continuación.
Sintaxis de la regla @property
Como hemos visto en el ejemplo anterior, para establecer una regla @property
debemos establecer la regla seguida de la variable CSS sobre la cuál va a actuar. En su interior debemos establecer tres propiedades:
Propiedad | Descripción |
---|---|
syntax | Indica la sintaxis (el tipo de dato) de la variable. |
inherits | Indica si la variable CSS debe heredarse o no. Valores true o false . |
initial-value | Indica cual es el valor por defecto de la variable CSS. |
Así pues, veamos otro ejemplo de declaración de @property
en acción. En este caso, hemos establecido un tipo de dato de color, para que se pueda animar el color:
@property --color {
syntax: "<color>";
inherits: false;
initial-value: red;
}
Como ves, muy sencillo.
Tipos de datos CSS de @property
Los valores posibles de la propiedad syntax
deben colocarse entre signos angulares <
y >
(como si fuera una etiqueta HTML) y podemos utilizar cualquiera de los siguientes:
Sintaxis posibles | Descripción | Ejemplos |
---|---|---|
<length> | Distancia/tamaño en una unidad CSS absoluta, relativa o de viewport. | 10px , 2rem , 90vw ... |
<percentage> | Única y exclusivamente valores de porcentajes. | 70% |
<length-percentage> | Permite valores de los dos tipos anteriores. | 10px , 3rem , 60% |
<angle> | Permite indicar ángulos: unidades como deg o turn , entre otras. | 45deg , 0.5turn |
<time> | Valores de tiempo, como por ejemplo, s o ms . | 5s , 500ms |
<resolution> | Indica valores de resolución, útiles en MQ, como dpi , dppx u otros. | 96dpi , 300dpi |
<integer> | Indica valores numéricos enteros, ya sean positivos o negativos. | 42 , 10 |
<number> | Permite tanto los valores anteriores, como valores decimales. | 4 , 4.6 |
<color> | Indica colores CSS en formato hexadecimal, rgb() u otros. | #485432 , #888 |
<custom-ident> | Valores personalizados por el usuario (similar a un string) | "nombre" ... |
<url> | Indica una URL mediante la función url() de CSS. | url(image.png) |
<image> | El tipo anterior o valores de gradientes CSS. | linear-gradient(...) ... |
<transform-function> | Funciones de transformación. | scale(1.2) o rotate(5deg) ... |
<transform-list> | Lista de varias funciones de transformación de las anteriores. | scale(2) translate(50px) ... |
El valor any
Por defecto, sin indicar una propiedad @property
, las variables CSS funcionan como lo hace Typescript de indicar el valor any
. Dicho de otra forma, acepta cualquier tipo de dato. Si queremos definir explícitamente este comportamiento podemos utilizar el asterisco:
@property --size {
syntax: "*";
inherits: false;
initial-value: small;
}
Sin embargo, la idea de @property
es justamente restringir el tipo de dato, no dejarlo abierto a cualquiera, que ya es el comportamiento por defecto. No obstante, podría existir alguna casuística donde queremos sobreescribir con ese comportamiento concreto de forma explícita.
Múltiples tipos
Sin embargo, también podemos hacer cosas un poco más avanzadas. En lugar de establecer un tipo de dato en la propiedad syntax
, podemos establecer un tipo de dato múltiple.
Esto nos permitirá establecer más de un tipo de dato en la misma variable CSS:
@property --size {
syntax: "small | large";
inherits: false;
initial-value: small;
}
En este caso, hemos indicado que la sintaxis de la variable CSS --size
puede ser tanto el valor de texto small
como large
. Además, observa que no hemos indicado un tipo de dato genérico, sino un dato muy concreto. También podríamos utilizar cosas como <integer> | <length>
si quisieramos permitir tanto números enteros como tamaños o longitudes con unidades.
Valores múltiples
Añadiendo ciertos carácteres podemos permitir múltiples valores en un tipo de dato, como ocurre por ejemplo en propiedades como background-image
cuando queremos añadir varias imágenes o gradientes. Para ello, al final de nuestra sintaxis utilizamos un caracter especial:
- Si añadimos el carácter
#
, nos permite valores separados por coma. - Si añadimos el carácter
+
, nos permite valores separados por espacio.
@property --gradient {
syntax: "<image>#";
inherits: false;
initial-value:
linear-gradient(to right, black, transparent),
linear-gradient(to bottom, transparent, indigo);
}
@property --size-list {
syntax: "<length>+";
inherits: false;
initial-value: 10px 0px 10px 0;
}
Usar @property
desde Javascript
Si estamos trabajando con Javascript, es posible definir estas variables CSS para añadirle su tipo de dato desde Javascript, con una sintaxis muy parecida a la que hacemos con la regla @property
. Para ello, utilizamos el método registerProperty()
del objeto CSS
.
Veamos el mismo ejemplo anterior, en su equivalente Javascript:
CSS.registerProperty({
name: "--color",
syntax: "<color>",
inherits: false,
initialValue: "red"
})
Observa, que al método registerProperty()
se le pasa un objeto que contendrá:
- 👩🎓 El nombre de la variable CSS mediante la propiedad
name
. - 👓 La sintaxis (tipo de dato) igual que se le aplica en CSS, con
syntax
. - 🎈 La propiedad
inherits
con un booleano que indica si se hereda o no. - ✨ El valor inicial de la variable CSS. Ojo que la propiedad se pasa a camelCase:
initialValue
.
Poco a poco se va ampliando el soporte de CSS Houdini en navegadores, y la regla @property
es uno de los mecanismos base para utilizar todo lo demás.