Cómo se decide hoy si puedes usar algo
Baseline, los dos umbrales que define, el criterio del modo de fallo y las tres formas reales de escribir un plan alternativo en CSS.
La pregunta “¿puedo usar esto?” tuvo durante quince años una respuesta pésima: mirar una tabla de porcentajes, elegir un umbral arbitrario y discutirlo en la revisión de código. Desde 2023 hay un vocabulario común —Baseline— que convierte esa conversación en algo decidible, y un criterio de ingeniería que casi nadie enuncia pero que importa más que el porcentaje: qué ocurre exactamente cuando la capacidad no está. Esta lección cierra el nivel de orientación con el procedimiento que usarás cada vez que aparezca algo nuevo.
- Diferenciar los dos umbrales de Baseline y elegir cuál aplica a un proyecto concreto.
- Clasificar una capacidad por su modo de fallo antes de decidir si se adopta.
- Escribir un plan alternativo con las tres técnicas disponibles y saber cuál toca.
- Reconocer qué preguntas no puede responder
@supports.
Los dos umbrales de Baseline
Baseline es un vocabulario compartido, mantenido por la comunidad WebDX y adoptado por la documentación de referencia y por las herramientas, que describe el estado de una capacidad web respecto a un conjunto fijo de navegadores: Chrome, Edge, Firefox y Safari, en sus versiones de escritorio y móvil. Define dos estados, y confundirlos es el error habitual.
Newly available: la capacidad funciona en todos los navegadores del conjunto, en su versión actual. Es decir, está terminada y es interoperable, pero mucha gente todavía no ha actualizado.
Widely available: han pasado treinta meses desde que alcanzó el estado anterior. Ese plazo no es una superstición: es aproximadamente el tiempo que tarda el parque real de dispositivos en renovarse lo suficiente como para que la cola de versiones antiguas deje de ser un problema para la mayoría de los sitios.
El umbral que aplica no es el mismo para todos. Un panel de administración interno con navegadores gestionados puede adoptar newly available el día uno. Una tienda que vende a público general en mercados con dispositivos antiguos hará bien en tratar widely available como su línea por defecto. Y un sitio con requisitos de accesibilidad estrictos tiene que mirar además si la degradación deja la interfaz utilizable, que es otra pregunta.
Lo que Baseline no dice es igual de importante. No dice si la implementación de los cuatro navegadores es igual de buena, solo si existe. No cubre los matices dentro de una misma capacidad: el anclaje de elementos está en Baseline desde enero de 2026, cuando Firefox 147 lo implementó, y sin embargo @position-try —la parte que reubica el elemento anclado cuando no cabe— exige Safari 18.4 o superior. Y no habla en absoluto de navegadores fuera del conjunto.
El criterio que decide de verdad: el modo de fallo
El porcentaje de soporte es el segundo criterio, no el primero. El primero es: si esto no está, ¿qué ve el usuario? Hay tres respuestas posibles y llevan a tres decisiones distintas.
| Modo de fallo | Qué ocurre sin soporte | Decisión |
|---|---|---|
| Cosmético | Se ve menos bonito, todo funciona | Adoptar sin plan alternativo |
| Degradado | Falta una comodidad, la tarea se completa | Adoptar con alternativa sencilla |
| Roto | Contenido ilegible, invisible o inoperable | No adoptar sin alternativa completa |
Una animación dirigida por scroll que decora una barra de progreso es cosmética: sin ella la barra se queda quieta y nadie se entera. Una transición de vista entre páginas es cosmética por definición, porque la navegación ocurre igual. Un @scope que acota estilos es degradado si lo peor que pasa es que unos estilos se filtren a un subárbol vecino, y roto si el estilo filtrado tapa contenido.
En cambio, construir el layout principal con una capacidad no universal y sin alternativa es la definición de fallo roto: si el motor no la entiende, descarta las declaraciones y el usuario se encuentra un montón de bloques apilados sin forma.
La consecuencia práctica es que el orden de la conversación se invierte respecto a lo que hace todo el mundo. No preguntes primero “¿está soportado?”, pregunta primero “¿qué pasa si no lo está?”. Si la respuesta es “nada grave”, el porcentaje deja de importar y puedes adoptar hoy.
Antes de escribir un @supports, comprueba si el descarte silencioso de declaraciones ya te resuelve el problema. El motor procesa las declaraciones de una regla una por una y tira las que no entiende, así que dos declaraciones consecutivas de la misma propiedad son un plan alternativo completo sin sintaxis adicional: la primera la entienden todos, la segunda solo los modernos, y el que entiende las dos se queda con la última por orden de aparición. Esto cubre la mayor parte de los casos de color, de unidades y de funciones de valor, y tiene una ventaja que se subestima: no puede desincronizarse, porque las dos versiones están una encima de la otra en la misma regla, y quien borre una verá inmediatamente la otra. Un @supports a veinte líneas de distancia se queda obsoleto en cuanto alguien cambia el valor de un lado y no del otro. La técnica tiene un límite exacto que hay que conocer: solo funciona cuando lo que varía es un valor, porque el descarte es por declaración. Si lo que necesitas es cambiar de estrategia entera —otro conjunto de propiedades, otra estructura de reglas—, ahí sí toca @supports. Y hay un caso donde no vale y duele: las custom properties son válidas con casi cualquier contenido, así que una segunda declaración de --color con un valor moderno no se descarta aunque el motor no sepa interpretarlo después; el fallo se traslada al punto de uso y aparece como un valor inválido en tiempo de computación, que se comporta de forma distinta. Con variables, detecta explícitamente.
Las tres formas de escribir el plan alternativo
Primera: el orden de declaraciones. La más barata, y la que hay que agotar antes de pasar a otra.
.aviso {
background: #1e66f5;
background: oklch(58% 0.19 258);
}
Un motor sin OKLCH descarta la segunda línea y se queda con el azul en sRGB. Uno moderno aplica la segunda porque aparece después. No hay condición, no hay duplicación de lógica y no hay nada que mantener sincronizado.
Segunda: @supports. Cuando lo que cambia es la estrategia, no el valor. Comprueba si el motor entiende un par propiedad y valor, y desde hace tiempo también si entiende un selector.
/* Camino base: todos los motores */
.rejilla {
display: flex;
flex-wrap: wrap;
gap: 1rem;
}
/* Mejora: solo donde exista subgrid */
@supports (grid-template-rows: subgrid) {
.rejilla {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr));
}
.rejilla > .tarjeta {
display: grid;
grid-row: span 3;
grid-template-rows: subgrid;
}
}
Para selectores la función es selector(), y acepta cualquier selector completo:
@supports selector(:has(> img)) {
.ficha:has(> img) { padding-block-start: 0; }
}
También existe la negación, útil cuando el camino moderno es el principal y el alternativo la excepción, aunque conviene usarla poco porque invierte la lógica de mejora progresiva:
@supports not (animation-timeline: scroll()) {
.indicador { display: none; }
}
Tercera: la capa de reserva del propio lenguaje. Muchas funciones aceptan un valor de reserva incorporado. var(--x, 1rem) usa 1rem si --x no está definida. env(safe-area-inset-bottom, 0px) hace lo propio con las variables de entorno. No es detección de soporte, es defensa contra la ausencia de valor, pero resuelve una familia entera de fallos.
Lo que @supports no puede contestar
Hay tres preguntas frecuentes que la regla condicional no responde, y dar por hecho que sí produce falsos positivos difíciles de diagnosticar.
No responde si la implementación es correcta o completa. @supports comprueba que el motor sabe analizar sintácticamente esa declaración, no que la implemente bien. Un motor puede reconocer la sintaxis de una propiedad y tener un comportamiento parcial.
No responde por capacidades que no son propiedades ni selectores: no puedes preguntar por una regla @ completa con la sintaxis básica, ni por una API de JavaScript, ni por si el dispositivo tiene GPU. Para lo primero existe @supports at-rule(...), que es reciente y no puedes dar por universal; para lo segundo, CSS.supports() desde JavaScript o directamente comprobar la existencia del objeto correspondiente.
Y no responde por el contexto del usuario: si prefiere menos movimiento, si el puntero es grueso, si el dispositivo tiene poca memoria. Eso son media queries de preferencia, que son una familia distinta y responden a otra pregunta: no “¿puede el motor?”, sino “¿quiere la persona?”. Ambas se combinan a menudo, y el orden correcto es comprobar primero la preferencia y después la capacidad, porque de nada sirve una animación soportada que el usuario ha pedido no ver.
- Elige una capacidad que hayas evitado usar por miedo al soporte y clasifícala en la tabla de modos de fallo.
- Escribe la versión base sin ella y la mejora encima, en ese orden, usando la técnica más barata de las tres que la resuelva.
- Desactiva la mejora comentando el bloque y comprueba que la versión base sigue siendo utilizable, no solo visible.