Elevador CSS: máquina de estado CSS pura con navegación de piso
Como desarrollador apasionado por la máquina de estado, a menudo me encuentro sufriendo de talMáquina de estado completa hecha por casillas de verificación HTML y CSS. «El poder de una máquina de estado impulsada por CSS pura me atrajo y comencé a preguntarme: podría crear algo más simple e interactivo, y no usar macros, lo que llevó a las simulaciones de ascensores de construcción de mi proyecto en CSS con indicadores de dirección, transiciones de animación, contadores, contadores e incluso accesibilidad.
En este artículo, lo llevaré a través de cómo usar las funciones de CSS modernas, como Propiedades personalizadas,,,,, encimeraeste :has() pseudo-nivel y @property – Cree un ascensor interactivo completamente funcional que sepa dónde está, a dónde va y cuánto tiempo llevará llegar allí. No se requiere JavaScript.
Definir estado con variables CSS
La columna vertebral del sistema de ascensores es utilizar propiedades personalizadas CSS para rastrear su estado. A continuación, he definido algunos @property Reglas que permiten los valores de transición y tipificación:
@property --current-floor {
syntax: "<integer>";
initial-value: 1;
inherits: true;
}
@property --previous {
syntax: "<number>";
initial-value: 1;
inherits: true;
}
@property --relative-speed {
syntax: "<number>";
initial-value: 4;
inherits: true;
}
@property --direction {
syntax: "<integer>";
initial-value: 0;
inherits: true;
}
Estas variables me permiten comparar el piso actual del elevador con el piso anterior, calcular la velocidad de movimiento y conducir la animación y la transición en consecuencia.
Propiedades personalizadas regulares de CSS (--current-floor) Muy adecuado para valores, Pero el navegador trata todo como una cadena: No sabe si 5 es un número, color o el nombre del gato. Si no lo sabe, no puede animarlo.
Ahí es donde @property Entra. Al «registrar» la variable, puedo decirle al navegador exactamente qué es (<number>,,,,, <length>etc), dale un valor de inicio y deja que maneje el suave en el medio. Sin ella, mi ascensor solo se doblaría del piso, que no era la experiencia de conducción que quería.
Una ui simple: los botones de radio para el piso
El botón de radio proporciona un disparador de estado. Cada piso corresponde a la entrada de radio, uso :has() Detectar cuál elegir:
<input type="radio" id="floor1" name="floor" value="1" checked>
<input type="radio" id="floor2" name="floor" value="2">
<input type="radio" id="floor3" name="floor" value="3">
<input type="radio" id="floor4" name="floor" value="4">
.elevator-system:has(#floor1:checked) {
--current-floor: 1;
--previous: var(--current-floor);
}
.elevator-system:has(#floor2:checked) {
--current-floor: 2;
--previous: var(--current-floor);
}
Esta combinación hace que el sistema de elevador sea una máquina de estado donde se selecciona un botón de radio para activar la transición y el cálculo.
Moverse a través de variables dinámicas
Para simular el movimiento del elevador, uso transform: translateY(...) Usar juntos --current-floor valor:
.elevator {
transform: translateY(calc((1 - var(--current-floor)) * var(--floor-height)));
transition: transform calc(var(--relative-speed) * 1s);
}
La duración del viaje es proporcional a cuántos pisos debe cruzar el elevador:
--abs: calc(abs(var(--current-floor) - var(--previous)));
--relative-speed: calc(1 + var(--abs));
Vamos a desglosarlo:
--absDado un número absoluto de pisos.--relative-speedHace la animación más lenta cuando se mueve más pisos.
Por lo tanto, si el elevador salta desde el primer piso hasta el cuarto piso, la animación dura más que desde el segundo piso hasta el tercer piso. Todo esto se deriva utilizando expresiones matemáticas en CSS calc() Función.
Determinar la dirección y el comportamiento de la flecha
La flecha del ascensor apunta hacia arriba o hacia abajo de acuerdo con el cambio en el piso:
--direction: clamp(-1, calc(var(--current-floor) - var(--previous)), 1);
.arrow {
scale: calc(var(--direction) * 2);
opacity: abs(var(--direction));
transition: all 0.15s ease-in-out;
}
Esto es lo que pasó:
- este
clamp()Resultados de límites funcionales-1y1. 1Significa movimiento ascendente,-1Es hacia abajo0Que significa quietud.- Este resultado se usa para escalar la flecha, voltearla y ajustar su opacidad en consecuencia.
Este es un método liviano que utiliza señales matemáticas y visuales para transmitir lógica direccional sin scripts.
Usando memoria simulada --delay
CSS almacena el estado anterior localmente. Retrasé la actualización de --previous propiedad:
.elevator-system {
transition: --previous calc(var(--delay) * 1s);
--delay: 1;
}
Tiempo de ejecución retrasado, --previous El valor se retrasa --current-floor. Esto me permite calcular la dirección y la velocidad durante la animación. Después de que termine el retraso, --previous ponerse al día. Este truco de memoria basado en retrasos permite que CSS se aproxime a las transiciones de estado utilizando JavaScript.
Estilización de contador de piso y unicode
Me alegro de mostrar los números de piso con gracia Mostrador de CSS:
#floor-display:before {
counter-reset: display var(--current-floor);
content: counter(display, top-display);
}
He definido un estilo de mostrador personalizado usando unicode concrighums:
@counter-style top-display {
system: cyclic;
symbols: "\278A" "\2781" "\2782" "\2783";
suffix: "";
}
este \278A llegar \2783 Los caracteres corresponden a los símbolos ➊, ➋, ➌, ➃ y le dan a la pantalla un encanto visual único. El elevador no solo dice «3», sino que también lo muestra en un estilo impreso. Este enfoque es conveniente cuando desea ir más allá del número original y aplicar símbolos o significados visuales.

Accesibilidad aria-live
La accesibilidad es importante. Si bien CSS no puede cambiar el texto de DOM, aún se puede usar para visualizar el contenido usando ScreenReader ::before y counter().
<div class="sr-only" aria-live="polite" id="floor-announcer"></div>
#floor-announcer::before {
counter-reset: floor var(--current-floor);
content: "Now on floor " counter(floor);
}
Agregar uno .sr-only Asistir a la clase Oculto visualmente, pero exponga a la tecnología de asistencia:
.sr-only {
position: absolute;
width: 1px;
height: 1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap;
}
Esto hace que la experiencia incluya la inclusión y alineada con los estándares de accesibilidad.
Aplicación práctica de estas tecnologías
Este ascensor es más que solo juguetes. Este es un plan. Considere estos usos del mundo real:
- Prototipo interactivo sin JavaScript
- Use el estado del campo como una forma de indicador de progreso
- UI del juego con inventario o mecánica de estado
- Rompecabezas lógicas o herramientas educativas (¡Seguimiento de estado solo para CSS!)
- Dependencias de JavaScript reducidas en el rendimiento o en los entornos de sandboxed
Estas técnicas son particularmente útiles en aplicaciones estáticas o entornos de secuencia de comandos restringidos (por ejemplo, correo electrónico, ciertos widgets del sistema de gestión de contenido).
El pensamiento final
El pequeño experimento inicial se convirtió en una máquina de estado CSS funcional que permite animaciones, señales y anuncia cambios sin JavaScript. CSS moderno puede hacer más de lo que a menudo damos. y :has(),,,,, @propertycontadores y algunas matemáticas inteligentes, puede construir sistemas reactivos, hermosos e incluso fáciles de usar.
Si intentas esta técnica, me encantaría ver lo que piensas. Y si reformate el ascensor (¿tal vez agregue más pisos o desafíos?), ¡Envíelo!