CSS aún no tiene switch
regla o condicional if
, aparte de la naturaleza específica de @media
consultas y algunos trucos profundos con propiedades personalizadas de CSS. Echemos un vistazo a por qué sería útil si lo hiciéramos, y veamos un truco que se puede utilizar hoy para lograrlo.
Charla reciente sobre la posibilidad
Si bien ninguna de estas cosas se puede usar hoy, ha habido una buena cantidad de conversaciones sobre el concepto de CSS condicional genérico solo en el último año:
- Brian Kardell propuso una
switch()
declaración y el riff de Tab Atkins al respecto. - Jonathan Neal propuso una variación de consulta de medios para valores condicionales que provocó bastante conversación.
- Lea Verou propuso “propiedades personalizadas de nivel superior” (aquí hay un vistazo a ellas de Bramus Van Damme) que parecen extraordinariamente útiles.
Entonces sí. La demanda de CSS condicional está ahí.
Imagina por qué sería útil CSS condicional
Quizás un cambio visual después de cierta cantidad de desplazamiento. Un cambio visual después de una entrada numérica está dentro de un cierto rango. Un componente con un puñado de estados.
Existe todo un género de bibliotecas de JavaScript extremadamente populares para UI (por ejemplo, React, Vue, etc.) que son esencialmente para construir UI basadas en el estado. Claramente, esta es una necesidad del desarrollador. Si pudiéramos mover ese estilo basado en el estado a CSS, sería menos JavaScript que necesitemos, y tal vez una mejor separación de preocupaciones.
Un tema común
Ya tenemos propiedades personalizadas en CSS, y podríamos basar la lógica de cambio de estado en ellas, cambiando un bloque de estilos como efecto secundario del cambio de la propiedad personalizada a ciertos valores.
Es cierto que ya tenemos mecanismos para cambiar bloques de estilos. Podemos cambiar class
a través de JavaScript, y que class
podemos aplicar lo que queramos en CSS. Pero eso no significa que el estilo basado en estados en CSS no sea útil. No siempre tenemos la capacidad o no queremos escribir JavaScript para esto, y en su lugar cambiamos las propiedades personalizadas de otras formas (por ejemplo, consultas de medios, cambios de HTML, etc.). Hacerlo en CSS significa ayudar a separar la lógica empresarial y la lógica de estilo visual.
¡Un truco! Utilizando @keyframes
para el estado
CSS @keyframes
puede ser usado para switch
cambios específicos. A través del poder del animation
propiedad, se abre una posibilidad para seleccionar exactamente qué marco mostrar, y hacer que se detenga exactamente en ese marco, imitando efectivamente una declaración de cambio de caso o estilos basados en el estado.
Veamos esto en acción jugando con el animation-delay
propiedad:
Esto es lo que está sucediendo en ese bolígrafo:
animation-delay
: Los valores de retardo negativos fuerzan a un fotograma específico (o entre) a tener efecto (los valores positivos no funcionan de esa manera). Usaremos este truco para forzar estados.animation-play-state: paused
: En realidad, no estamos animando nada, por lo que la animación permanecerá en pausa.animation-duration
: La duración real no importa, solo necesita una, por lo que hay un período de tiempo para mantener los diferentes fotogramas clave. Lo convertiremos en un valor como100.001s
para que si nos demoramos100s
, el último fotograma clave seguirá funcionando. La duración debe ser mayor que el valor de retardo.
La primera entrada de rango modifica el animation-delay
entre un rango de -100s
y 0s
.
Un caso de uso del mundo real
Antes de pasar directamente al ejemplo práctico, vale la pena discutir este truco con más detalle porque hay algunos matices que debe conocer.
En primer lugar, el truco solo funciona con valores numéricos. Entonces, valores de color o cadenas porque es estrictamente matemático.
En segundo lugar, está el truco booleano. Considere una variable --value: 10
que puede tomar cualquier valor numérico entre 0 y 100. Queremos aplicar color si el valor está por encima de 5. ¿Cómo sabemos si el valor está por encima o por debajo de 5? E incluso si lo sabemos, ¿cómo nos ayuda realmente eso?
--is-above-5: clamp(0, var(--value) - 5, 1)
--value |
--is-above-5 |
Resultado |
---|---|---|
0 | 0 | 0-5 = -5, clamp() fuerza un valor no menor a 0 |
2 | 0 | 2 – 5 = -3, clamp() fuerza un valor no menor a 0 |
5 | 0 | 5 – 5 = 0 |
7 | 1 | 7 – 5 = 2, clamp() fuerza un valor no mayor que 1 |
clamp()
es como un inteligente calc()
, ya que nos permite limitar estrictamente un valor calculado al rango mientras declaramos un valor ideal. Ese rango es todo lo que se necesita para lograr una variable booleana.
Escriba cualquier matemática en el segundo parámetro de la clamp()
y eso generará 0 (o menos) o 1 (o más). Asegúrese de no escribir ninguna matemática que pueda resultar en un número entre 0 y 1.
Así es como funciona eso:
El único trabajo de la entrada de rango es “difundir” su valor definiendo valores para --value
, --min
y --max
, luego modificando el --value
usando un oninput
evento. Eso es lo más mínimo que se puede hacer para obtener un comportamiento similar a un estado en CSS. No se necesita JavaScript.
Usando funciones matemáticas CSS, es posible inferir el porcentaje “completado” de la barra de progreso a partir de esas mismas variables:
--completed: calc((var(--value) - var(--min) ) / (var(--max) - var(--min)) * 100);
Ahora, sabemos si el valor está por encima de cierto porcentaje, lo que nos brinda otra forma de realizar cambios por estado:
--over-30: clamp(0, var(--completed) - 30, 1);
--over-70: clamp(0, var(--completed) - 70, 1);
/* ...and so on... */
Bien, genial, pero ¿cómo podemos usar esto para seleccionar un fotograma clave específico? Mediante el uso max()
función:
--frame: max(
calc(1 - var(--over-30)),
var(--over-30) * 2,
var(--over-70) * 3,
var(--is-100) * 4
);
Lo que pasa con los valores booleanos de CSS es que hay muchas formas de usarlos para lograr un objetivo determinado, y uno debe ser creativo, encontrar una fórmula que sea corta y legible.
En la fórmula anterior, los valores booleanos “alternarán” un número de fotograma si el valor booleano tiene el valor de 1
. Dado que estamos usando un max
función, el mayor número de fotogramas alternados será el valor calculado de --frame
.
Tenga en cuenta que el cambio de color tiene una ligera transición. Podríamos haber hecho esto con el background: currentColor;
en el área de relleno, que hereda el color del padre, pero elegí usar CSS Houdini para ilustrar el poder de asignar transiciones a variables CSS declarando su type
.
Un ejemplo de un uso intensivo Truco booleano CSS se puede ver en el lápiz a continuación, que es un componente solo de CSS con muchas variables que permiten una amplia gama de personalización:
Estoy seguro de que hay muchos otros casos de uso para este pequeño truco y estoy emocionado de ver qué más se puede lograr con la creatividad de la comunidad.