La regla @property

Tipos de datos en CSS


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.

Sintaxis múltiple

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.

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
<length> Indicamos una distancia o tamaño en una unidad CSS, ya sea absoluta, relativa o de viewport.
<length-percentage> Permite tanto las unidades anteriores como los valores de porcentaje.
<percentage> Indica sólo y exclusivamente valores de porcentajes.
<angle> Permite indicar ángulos, con unidades como deg o turn, entre otras.
<time> Indica valores de tiempo, como por ejemplo, s o ms.
<resolution> Permite indicar valores de resolución, muy útiles en media queries, como dpi, dppx u otros.
<integer> Indica valores numéricos enteros, ya sean positivos o negativos.
<number> Permite tanto los valores anteriores, como valores decimales.
<color> Permite indicar colores CSS, mediante sintaxis hexadecimal, rgb() u otras.
<custom-ident> Valores personalizados por el usuario, similar a un string: nombre de animaciones, propiedades, etc.
<url> Indica una URL mediante la función url() de CSS.
<image> Permite indicar los valores anteriores de url() o gradientes CSS.
<transform-function> Indica una función de transformación como translate(), scale() o similares.
<transform-list> Permite una combinación de varias funciones de transformación de las anteriores.

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.

¿Quién soy yo?

Soy Manz, vivo en Tenerife (España) y soy streamer partner en Twitch y profesor. Me apasiona el universo de la programación web, el diseño y desarrollo web y la tecnología en general. Aunque soy full-stack, mi pasión es el front-end, la terminal y crear cosas divertidas y locas.

Puedes encontrar más sobre mi en Manz.dev