También disponible en English.
El problema
Un equipo entrega CSS limpio.
Cada selector es deliberado. Cada nombre de clase significa algo. Las revisiones de código detectan lo descuidado antes de integrarlo.
Seis meses después, alguien añade !important para arreglar un botón.
Un año después, existen tres !important más — cada uno escrito para arreglar el anterior. Nadie planeó esto. Nadie dejó de prestar atención. El equipo es exactamente tan disciplinado como el primer día.
La base de código no se volvió descuidada. La arquitectura nunca tuvo una forma de mantenerse limpia.
Esa es la parte que vale la pena analizar. Los problemas de especificidad se tratan como un fallo de disciplina — nombres malos, anidamiento descuidado, alguien con prisa. Pero los equipos con una disciplina excelente también chocan con este muro. Con suficiente tiempo y suficientes colaboradores, casi toda base de código de CSS deriva hacia el mismo lugar: ajustes sobre ajustes, cada uno un parche para el anterior. Aquí ocurre algo estructural. No es un problema de personas. Es un vacío en las herramientas.
Por qué existe el problema
La especificidad de CSS fue construida para responder una sola pregunta: si dos reglas apuntan al mismo elemento, ¿cuál gana?
El navegador calcula una respuesta. Cuenta los IDs. Cuenta las clases y los atributos. Cuenta los elementos. El número más alto gana. Si hay empate, gana la regla que aparezca más tarde en el orden del archivo.
Ese es todo el mecanismo. Es rápido, determinista, y nunca se diseñó para hacer más que eso.
Nota lo que no pregunta. No pregunta si una regla es un valor por defecto fundamental o una excepción única. No pregunta si una regla fue escrita para ser sobrescrita, o para no ser tocada nunca más. No conoce la diferencia entre un estilo base y una clase de utilidad — solo conoce cuántos selectores usó cada uno.
La especificidad resuelve conflictos. Nunca se le dio una forma de codificar la intención.
Ese vacío es antiguo. Es anterior a la arquitectura de frontend basada en componentes, a los sistemas de diseño y a los equipos de cien ingenieros tocando la misma hoja de estilos. La plataforma web dio a los desarrolladores un sistema de puntuación para saber qué regla gana por los números — y luego la industria siguió construyendo sistemas cada vez más grandes sobre un mecanismo que no tiene concepto de qué regla debería ganar por diseño.
El intercambio es real, y vale la pena nombrarlo claramente: la especificidad le da al navegador algo valioso — una forma rápida y predecible de resolver cualquier conflicto sin preguntar nada al autor. Lo que cuesta es igualmente real. Los ingenieros no tienen una forma integrada de decir "esto siempre gana" o "esto siempre pierde". Tienen que simular eso con el peso del selector, y el peso del selector nunca fue construido para cargar significado.
El Primer Principio
Aquí está el cálculo, de forma concreta.
.card .title suma tres puntos — dos clases y un elemento. El contexto más allá de eso no se cuenta igual, pero la regla se mantiene: dos clases pesan más que un elemento. h2 suma un punto. Es un selector de un solo elemento.
Así que .card .title gana a h2. Siempre. Sin importar qué regla se escribió primero. Sin importar cuál debía ser el valor de reserva y cuál la sobrescritura. El navegador no conoce la intención. Solo conoce la cuenta.
Ahora extiende eso. Una clase de utilidad destinada a sobrescribirlo todo —.text-center, por ejemplo— tiene el mismo peso que cualquier otra clase individual. Puede perder contra .card .title aunque su único propósito fuera ganar. La intención del autor y el peso del selector han divergido silenciosamente, y nada en el sistema les dirá nunca que eso ocurrió. La página simplemente se renderizará mal, y alguien irá a buscar el porqué. La página simplemente se renderizará mal, y alguien irá a buscar el porqué.
Este es el principio que vale la pena nombrar directamente: la especificidad es un cálculo, no una decisión. La cascada no tiene concepto de "esta capa debería ganar siempre porque es una utilidad" o "esto debería perder siempre porque es un valor por defecto fundamental". Esas categorías aún no existen para el navegador. Todo lo que tiene es aritmética.
Demostrando el principio
Toma un estilo base simple:
.card .title {
font-size: 1.25rem;
color: #1a1a1a;
}
Y una sobrescritura de componente, escrita después, con la intención de ganar:
h2 {
font-size: 2rem;
}
La regla de h2 pierde. No porque esté mal — porque es un selector de un solo elemento luchando contra un selector de dos clases, y la cuenta siempre decide. El arreglo, tácticamente, se ve así:
.card h2.title {
font-size: 2rem;
}
Más específico. Ahora gana. También acaba de hacer que la siguiente sobrescritura sea más difícil, porque el próximo desarrollador que necesite tocar este elemento tiene que superar este selector, lo que significa escribir algo aún más pesado. Seis meses después, alguien añade !important para sobrescribir eso. El patrón se repite, cada arreglo un poco más contundente que el anterior, hasta que la hoja de estilos es una pila de parches cada vez más específicos sin registro de cuál debe ser realmente la fuente de verdad.
Nadie eligió este resultado. Cada arreglo individual fue razonable. Eso es lo que hace que valga la pena detenerse.
Hacia dónde va esto
Hay un arreglo real para esto — y no es escribir selectores con más cuidado, o acordar como equipo no usar nunca IDs, o prohibir !important en una regla de linting. Todos esos son intentos de gestionar el síntoma con más disciplina, y la disciplina por sí sola no escala mejor que la especificidad.
El arreglo real es arquitectónico. Significa dar a la cascada algo que nunca se le dio por defecto: un eje de orden explícito, independiente de la especificidad, donde la precedencia se declara en lugar de calcularse, dentro de un sistema de contratos que todo el equipo puede ver
Ese mecanismo existe. Es nativo del navegador, se entrega sin pasos de compilación — y merece su propia pieza, más adelante en esta serie.
La lección general
Aléjate de CSS por un momento.
Cualquier sistema que permita que los resultados se decidan por un efecto secundario aritmético —en lugar de un contrato declarado e intencional— derivará con el tiempo. No importa cuán cuidadosas sean las personas que lo usan. Con suficientes colaboradores y suficiente tiempo, los sistemas implícitos acumulan conocimiento implícito: reglas tribales sobre qué archivos tocar, qué selectores son "seguros", cuáles nadie se atreve a cambiar. Ese conocimiento vive en la cabeza de las personas, no en el sistema, y se evapora en el momento en que esas personas se van.
La especificidad de CSS es un ejemplo de un patrón que aparece en todo el software: la precedencia sin un mecanismo para expresar la intención es una precedencia que eventualmente se vuelve impredecible. El navegador dio a los desarrolladores una herramienta de resolución de conflictos y lo dio por terminado. Pasaron años antes de que la plataforma diera a los autores algo más cercano a lo que realmente necesitaban — y más tiempo aún antes de que la mayoría de los equipos notaran que la arquitectura, no la disciplina, fue la pieza faltante todo este tiempo.
Top comments (0)