CSS custom properties acotadas y polivalentes 5.4.16
El alcance (cascada) de las propiedades CSS de autor o CSS custom properties en función de donde se declaren y la posibilidad de usar el mismo nombre con distintos valores en diferentes reglas CSS.
CSS custom properties acotadas y polivalentes
A estas alturas ya es sabido por todos (y si no calla y sigue leyendo ;-) que el alcance de las CSS custom properties
o "declaraciones CSS de autor" depende de dónde se declare la equivalencia --nombre: valor;
Así, según en qué regla lo hagamos podemos clasificar las custom properties
en función de su alcance en dos grupos:
- Globales
- Locales o acotadas (scoped)
Custom properties globales
Sólo necesitamos declarar la equivalencia --customName: valor;
o bien en :root {}
, html {}
o body {}
para que podamos usarla en cualquier elemento del documento. Estaríamos ante una "propiedad de autor" de alcance global
.
Su uso propiedad: var(--valor)
en cualquier regla CSS será computado y usado (siempre que no sea pisado por ningún otro valor ya sea por herencia o cascada).
Custom properties acotadas (scoped)
Otra forma de usar las custom properties
es establecer la equivalencia en el bloque de declaraciones CSS de un selector concreto distinto de los anteriores:
article {
--miProp: blue;
}
p {
color: var(--miProp);
}
Haciéndolo así única y exclusivamente los párrafos contenidos algún article
serán mostrados en azul. En cualquier otro párrafo color: var(--miProp)
no será computada. O mejor dicho, su cómputo será nulo y por lo tanto de no aplicación.
Estamos ante una "declaración de autor" de alcance local o acotada (CSS scoped).
Esta particularidad con los valores usados en el ejemplo no parece tener "mucha chicha", ¿verdad? Bueno, espera y sigue leyendo.
Custom properties polivalentes
Hace unas fechas Furoya en un intercambio epistolar me planteaba un pequeño reto relativo a uno de sus iconos CSS "single element". En concreto uno que me permite compartir contigo en primicia:
Newton's Cradle ['bolas de Newton animadas']
Autor: Furoya
La animación requiere 2 reglas @keyframes
Antes de seguir con "lo nuestro" te invito a que te fijes cómo crea las cinco bolas siendo un single element"
.
La cuestión es la siguiente: como tenemos dos elementos (las dos bolas de los extremos) con un movimiento (rotate) igual pero de signos opuestos (una gira hacia la izquierda y la otra a la derecha) se necesitan dos reglas @keyframes
iguales pero con una transformación de giro de signo contrario en la segunda:
@keyframes pendulumI {
0%, 50%, 100% {transform: rotate(0);}
25% {transform: rotate(25deg);}
}
@keyframes pendulumD {
0%, 50%, 100% {transform: rotate(0);}
25% {transform: rotate(-25deg);}
}
.izquierda {
animation: pendulumI .... ;
}
.derecha {
animatión: pendulumD ... ;
}
Y el reto consistía, ya que estaba minimizando el marcado HTML a un sólo elemento, hacer lo mismo con el CSS y lograr el mismo efecto con una sola regla @Keyrame
.
Mi primer intento fue emplear las propiedades rotate y/o scale en una de las bolas para invertirla (a semejanza del "truco" base del post "Rueda la rueda del ratón ¿hacia dónde va el scroll?") y así poder usar en la animación la propiedad transform
sin que se viese afectada la inversión previa.
Custom properties: mismo nombre, múltiples valores diferentes
Intento que deseché nada más meditarlo un poco y porque recordé las "propiedades de autor". En concreto dos de sus particularidades:
- Las "custom properties" acotadas sólo son computadas para el elemento al que apunta la regla CSS en la que están declaradas.
- Una consecuencia de lo anterior es que nada impide que una "custom property" con el mismo nombre se use en dos reglas distintas con valor diferente en cada una de ellas.
Volvamos al Código 1, el ejemplo del apartado Custom properties acotadas
y a su semejanza declaremos:
article {
--miProp: blue;
}
footer {
--miProp: red;
}
p {color: var(--miProp);}
La consecuencia de ello es que los párrafos contenidos en los article
se mostrarán en azul y aquellos que se encuentren en el footer
serán rojos.
Recuerda que el nombre oficial del documento que las desarrolla es "CSS Custom Properties for Cascading Variables". Y la expresión cascading variables
es la clave.
Aplicación práctica
Retomemos el reto de Furoya y apliquemos esta particularidad de las variables en cascada
a sus bolas:
.izq, .dch {
animation: pendulem ...; /*misma animación para ambos*/
}
.izq {
--miGiro: rotate(25deg);
}
.derecha {
--miGiro: rotate(-25deg);
}
@keyframes pendulum {
0%, 50%, 100% {transform: rotate(0);}
25% {transform: var(--miGiro);}
/*el valor computado está en función del declarado para cada
--miGiro que hayamos establecido en cada regla*/
}
El resultado lo puedes ver a continuación. Y aunque el resultado (el efecto visual logrado) es exáctamente igual que el anterior...
Newton's Cradle ['bolas de Newton animadas']
Autor: Furoya
Usando custom properties
sólo es necesaria una animación
...si le hechas un vistazo al inspector verás que sólo se necesita una (y la misma) regla @keyframes
para obtener dos movimientos diferentes de las bolas (igual rotación con signo contrario).
Pese a ser la misma animación para ambos elementos, el valor computado de transform: var(--miGiro);
es distinto en cada uno de ellos.
Porque recuerda: a diferencia de lo que ocurre con las 'variables' nativas de los procesadores CSS que son sustituidas por su valor al mandar los estilos al navegador (y por lo tanto desaparecen como tales del código CSS) las 'custom properties" nativas de CSS se mantienen inmutables en el código recibido por el navegador; y en vez de sustituirlas lo que ocurre es que su valor es computado cada vez que el navegador se topa con ellas
.
Lecturas complementarias
Las Custom Properties no son variables CSS. Pero molan
CSS Custom Properties for Cascading Variables Module Level 1 llamadas erróneamente en ocasiones como variables CSS. El porqué, un poco de su historia, cómo usarlas y diferencia con las variables de las herramientas para manejar CSS (procesadores)
.
Kseso
the obCSServer ᛯ Ramajero Argonauta, Enredique Amanuense de CSS.#impoCSSible inside
Dicen que, en español, EsCss es el mejor blog de CSS. Posíblemente exageren.
@Kseso EsCss Kseso
Muy ingenioso. Te agradecí en privado pero es justo que también lo haga en público.
ResponderEliminarYa agregué al pen que enlazaste más arriba el ícono en cuestión, con su correspondiente crédito en el código fuente. Los hago como laborterapia, nunca pensé que alguno sirviera de inspiración para un artículo, así que estoy feliz con este resultado. Seguramente alguien va a tomar nota y va a aplicar en sus proyectos este uso de las variables de autor.
Pensaba en estos péndulos y lo extraño de haber esperado hasta ahora para crear su ícono, ya que es un juego que tengo presente desde mi infancia. De hecho, una vez escribí un breve cuento como excusa para contar otras historias (al que titulé "Rompiendo las bolas de Newton"), del que ya no quedan rastros en la web, porque el sitio donde estaba publicado hoy no existe.
Cuando tenga más problemas para resolver mis iconitos, te aviso XD .
Un abrazo.
Bueno, no tengo dificultades de animación para mis íconos, pero si encontré un "problema" extraño de alguien que no quería que su cliente modificara la style sheet, pero sí le permitía editar el contenido HTML. No es que realmente me importe mucho el caso, pero me puso a pensar en cómo resolverlo.
ResponderEliminarEl drama aparece en las pseudoclases como ':hover', porque no existen en el HTML, sólo se generan a partir de las declaraciones CSS y se modifican en la hoja de estilos.
Resulta que se puede exprimir un poco más esto de las custom properties, y agregarlas como estilos inline para asociarlas a lo que dejemos puesto previamente en un archivo '.css' . Acá hay un ejemplo, donde existe un valor de color para el elemento padre, que modifica el ':hover' de sus enlaces hijos, excepto a uno, que tiene su propio valor de color y pesa más que el de su padre. Por supuesto, todos son referidos por la pseudoclase declarada en la hoja de estilos, porque —insisto— a ':hover' no lo podemos poner "en línea".
[code]
<!DOCTYPE html>
<html lang="es-ar">
<head>
<meta charset="utf-8" />
<style type="text/css">
body {
color: orange;
}
a {
font-size: 30px;
/* --colorHover: violet; */
}
a:hover {
color: var(--colorHover);
}
</style>
</head>
<body>
<div style="--colorHover: red; ">
<a href="#">Hover <del>violeta en hoja estilos</del> rojo inline en elemento padre. </a><br>
<a href="#" style="--colorHover: green;">Hover verde inline. </a><br>
<a href="#">Hover <del>violeta en hoja estilos</del> rojo inline en elemento padre. </a><br>
</div>
<div>
<a href="#">Hover anaranjado por hoja estilos para <code>body</code>. </a>
</div>
</body>
</html>
[/code]
Un detalle importante, que casi hace (más) inútil este experimento: si hay otros enlaces fuera de nuestra prueba, el color que aparece el pasar el puntero es el declarado para el ancestro, ya no se puede modificar el valor para 'color: var(--colorHover)' , y no habrá un color alternativo hasta que la función 'color()' trabaje en todos los navegadores.
Otro detalle importante, es que si a los anchor les declaramos el valor de color usando el mismo nombre de variable, para que lo tome como ancestro directo, este color "pisa" al que tenga declarado 'inline'. Es decir, que en este caso la declaración de la hoja de estilos pesa más que la declaración en línea. Se puede probar descomentando '--colorHover: violet;' .
Si a alguien le sirve ...